initial commit
This commit is contained in:
100
pkg/tasks/tasks.go
Normal file
100
pkg/tasks/tasks.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Simple in-memory task registry placeholder. Replace with durable store if needed.
|
||||
type Task struct {
|
||||
ID string
|
||||
Status string
|
||||
Result interface{}
|
||||
Err string
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
mu sync.Mutex
|
||||
tasks map[string]Task
|
||||
workChan chan workItem
|
||||
}
|
||||
|
||||
type workItem struct {
|
||||
taskID string
|
||||
fn WorkFunc
|
||||
}
|
||||
|
||||
// WorkFunc performs the actual task work.
|
||||
type WorkFunc func(ctx context.Context) (interface{}, error)
|
||||
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
tasks: make(map[string]Task),
|
||||
workChan: make(chan workItem, 64),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registry) Add(t Task) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.tasks[t.ID] = t
|
||||
}
|
||||
|
||||
// EnqueueWork registers a task and queues it for asynchronous processing.
|
||||
func (r *Registry) EnqueueWork(id string, fn WorkFunc) {
|
||||
r.Add(Task{ID: id, Status: "queued"})
|
||||
r.workChan <- workItem{taskID: id, fn: fn}
|
||||
}
|
||||
|
||||
func (r *Registry) Update(id string, status string, result interface{}) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if t, ok := r.tasks[id]; ok {
|
||||
t.Status = status
|
||||
t.Result = result
|
||||
r.tasks[id] = t
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registry) Fail(id string, err error) {
|
||||
if err == nil {
|
||||
err = errors.New("unknown error")
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if t, ok := r.tasks[id]; ok {
|
||||
t.Status = "error"
|
||||
t.Err = err.Error()
|
||||
r.tasks[id] = t
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registry) Get(id string) (Task, bool) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
t, ok := r.tasks[id]
|
||||
return t, ok
|
||||
}
|
||||
|
||||
// StartWorker processes queued work sequentially. Caller should run this in a goroutine.
|
||||
func (r *Registry) StartWorker(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case item := <-r.workChan:
|
||||
r.runItem(ctx, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registry) runItem(ctx context.Context, item workItem) {
|
||||
r.Update(item.taskID, "running", nil)
|
||||
res, err := item.fn(ctx)
|
||||
if err != nil {
|
||||
r.Fail(item.taskID, err)
|
||||
return
|
||||
}
|
||||
r.Update(item.taskID, "completed", res)
|
||||
}
|
||||
Reference in New Issue
Block a user