Sobes.tech
Senior

// Write an asynchronous task handler as a library // The client passes an object (Task) with data for execution, // in our example, a simple structure is used. // The handler can process no more than N tasks simultaneously, // and no more than X tasks can be queued for processing. // If there is no space in the queue, return an error to the client immediately. // A task is taken for processing if there are free handlers. // Simulate processing duration with time.Sleep(5*time.Second). // When a task completes, the next task from the queue is taken. // If the queue is empty, wait for new tasks from clients. // With a star: extend the Task structure and get task statuses via a separate request package scheduler type Scheduler interface { AddTask(t Task) error Close() } type Task interface { Do() }

sobes.tech AI

Answer from AI

go package scheduler

import ( "errors" "sync" "time" )

type Task interface { Do() }

type taskWrapper struct { task Task status string // "queued", "running", "done", "error" }

type Scheduler interface { AddTask(t Task) error Close() GetStatus(id int) (string, error) }

type scheduler struct { maxWorkers int maxQueue int queue chan *taskWrapper wg sync.WaitGroup closed bool mu sync.Mutex tasks map[int]*taskWrapper nextID int }

func NewScheduler(maxWorkers, maxQueue int) Scheduler { s := &scheduler{ maxWorkers: maxWorkers, maxQueue: maxQueue, queue: make(chan *taskWrapper, maxQueue), tasks: make(map[int]*taskWrapper), }

for i := 0; i < maxWorkers; i++ {
	go s.worker()
}

return s

}

func (s *scheduler) AddTask(t Task) error { s.mu.Lock() defer s.mu.Unlock()

if s.closed {
	return errors.New("scheduler is closed")
}

if len(s.queue) >= s.maxQueue {
	return errors.New("queue is full")
}

id := s.nextID
s.nextID++

tw := &taskWrapper{task: t, status: "queued"}
s.tasks[id] = tw
s.queue <- tw

return nil

}

func (s *scheduler) worker() { for tw := range s.queue { s.mu.Lock() tw.status = "running" s.mu.Unlock()

	// Simulate long processing
	tw.task.Do()

	s.mu.Lock()
	tw.status = "done"
	s.mu.Unlock()
}

}

func (s *scheduler) Close() { s.mu.Lock() if s.closed { s.mu.Unlock() return } close(s.queue) s.closed = true s.mu.Unlock() }

func (s *scheduler) GetStatus(id int) (string, error) { s.mu.Lock() defer s.mu.Unlock()

tw, ok := s.tasks[id]
if !ok {
	return "", errors.New("task not found")
}
return tw.status, nil

}

// Example implementation of Task // type MyTask struct{} // func (t MyTask) Do() { // time.Sleep(5 * time.Second) // }


In this example:
- Scheduler limits the number of tasks executed simultaneously (maxWorkers).
- Task queue is limited in size (maxQueue).
- If the queue is full, AddTask returns an error.
- Each task has a status that can be retrieved via GetStatus.
- Task processing is simulated by calling Do(), where time.Sleep can be used.
- Scheduler can be closed, after which new tasks are not accepted.
// Write an asynchronous task handler as a library //… - sobes.tech