package tasks import ( "crypto/rand" "encoding/hex" "sync" "time" ) type Status string const ( StatusRunning Status = "running" StatusSuccess Status = "success" StatusFailed Status = "failed" ) type Task struct { ID string `json:"id"` Type string `json:"type"` Status Status `json:"status"` StartedAtMS int64 `json:"started_at_ms"` EndedAtMS int64 `json:"ended_at_ms,omitempty"` Error string `json:"error,omitempty"` Result any `json:"result,omitempty"` } type Registry struct { mu sync.Mutex tasks map[string]Task } func NewRegistry() *Registry { return &Registry{tasks: map[string]Task{}} } func (r *Registry) Start(typ string) Task { r.mu.Lock() defer r.mu.Unlock() id := newID() t := Task{ ID: id, Type: typ, Status: StatusRunning, StartedAtMS: time.Now().UnixMilli(), } r.tasks[id] = t return t } func (r *Registry) Finish(id string, result any, err error) (Task, bool) { r.mu.Lock() defer r.mu.Unlock() t, ok := r.tasks[id] if !ok { return Task{}, false } if err != nil { t.Status = StatusFailed t.Error = err.Error() } else { t.Status = StatusSuccess t.Result = result } t.EndedAtMS = time.Now().UnixMilli() r.tasks[id] = t return t, true } func (r *Registry) Get(id string) (Task, bool) { r.mu.Lock() defer r.mu.Unlock() t, ok := r.tasks[id] return t, ok } func newID() string { b := make([]byte, 16) if _, err := rand.Read(b); err != nil { return hex.EncodeToString([]byte(time.Now().Format("20060102150405.000"))) } return hex.EncodeToString(b) }