Sobes.tech
Senior

// Write an asynchronous task handler as a library // The client passes an object (Task) with data for executing the task, // in our example, we will use an empty structure. // 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, immediately return an error to the client. // A task is taken for processing if there are free handlers available. // Simulate processing duration with time.Sleep(5*time.Second). // As soon as one task is completed, take the next task from the queue. // If the queue is empty, wait for new tasks from clients. // With a star: extend the Task structure and get task statuses through a separate request.

sobes.tech AI

Answer from AI

go package taskhandler

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

type Task struct { ID int Status string // "queued", "processing", "done", "error" }

type Handler struct { maxWorkers int maxQueue int queue chan *Task wg sync.WaitGroup mu sync.Mutex tasks map[int]*Task workerSem chan struct{} idCounter int }

func NewHandler(maxWorkers, maxQueue int) *Handler { h := &Handler{ maxWorkers: maxWorkers, maxQueue: maxQueue, queue: make(chan *Task, maxQueue), tasks: make(map[int]*Task), workerSem: make(chan struct{}, maxWorkers), } go h.dispatch() return h }

func (h *Handler) Submit(task *Task) (int, error) { h.mu.Lock() defer h.mu.Unlock()

if len(h.queue) >= h.maxQueue {
	return 0, errors.New("queue is full")
}
h.idCounter++
task.ID = h.idCounter
task.Status = "queued"
h.tasks[task.ID] = task
h.queue <- task
return task.ID, nil

}

func (h *Handler) dispatch() { for task := range h.queue { h.workerSem <- struct{}{} // acquire worker slot h.wg.Add(1) go h.process(task) } }

func (h *Handler) process(task *Task) { defer func() { <-h.workerSem // release worker slot h.wg.Done() }()

// Update status
h.mu.Lock()
task.Status = "processing"
h.mu.Unlock()

// Simulate long processing
time.Sleep(5 * time.Second)

// Finish task
h.mu.Lock()
task.Status = "done"
h.mu.Unlock()

}

func (h *Handler) Status(taskID int) (string, error) { h.mu.Lock() defer h.mu.Unlock() if task, ok := h.tasks[taskID]; ok { return task.Status, nil } return "", errors.New("task not found") }

func (h *Handler) Shutdown() { close(h.queue) h.wg.Wait() }

This code implements an asynchronous task handler with limits on the number of concurrently processed tasks (maxWorkers) and the queue size (maxQueue). If the queue is full, Submit returns an error. Task statuses can be retrieved via the Status method by task ID.