package scheduler import ( "context" "cycle-scheduler/internal/job" "sync/atomic" "time" ) // atomicTimer wraps a `time.Timer`. type atomicTimer struct { atomic.Pointer[time.Timer] } func (at *atomicTimer) stop() { timer := at.Load() if timer != nil { timer.Stop() } } // set replaces the current timer. // It also ensures that the current timer is stopped. func (at *atomicTimer) set(t *time.Timer) { timer := at.Load() if timer != nil { timer.Stop() at.Swap(t) return } at.Swap(t) } type TaskDetails struct { job.JobDetails Attempts int `json:"attempts"` } type task struct { *job.Job attempts atomic.Uint32 timer atomicTimer } func newTask(f job.FnJob) *task { j := job.NewJob(f) t := task{ Job: &j, timer: atomicTimer{}, } return &t } func (t *task) abort() { t.timer.stop() t.Job.Abort() } func (t *task) run(ctx context.Context) { t.attempts.Add(1) t.Job.Run(ctx) } func (t *task) getDetails() TaskDetails { return TaskDetails{ JobDetails: t.IntoDetails(), Attempts: int(t.attempts.Load()), } }