77 lines
1.1 KiB
Go
77 lines
1.1 KiB
Go
package scheduler
|
|
|
|
import (
|
|
"context"
|
|
"cycle-scheduler/internal/job"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// safeTime wraps a `time.Timer` with a lock to be thread safe.
|
|
type safeTimer struct {
|
|
l sync.Mutex
|
|
timer *time.Timer
|
|
}
|
|
|
|
func (st *safeTimer) stop() {
|
|
if st.timer != nil {
|
|
st.timer.Stop()
|
|
}
|
|
}
|
|
|
|
// set replaces the current timer.
|
|
// It also ensures that the current timer is stopped.
|
|
func (st *safeTimer) set(t *time.Timer) {
|
|
st.l.Lock()
|
|
defer st.l.Unlock()
|
|
|
|
if st.timer != nil {
|
|
st.timer.Stop()
|
|
st.timer = t
|
|
return
|
|
}
|
|
|
|
st.timer = t
|
|
}
|
|
|
|
type TaskDetails struct {
|
|
job.JobDetails
|
|
Attempts int `json:"attempts"`
|
|
}
|
|
|
|
type task struct {
|
|
*job.Job
|
|
attempts atomic.Uint32
|
|
timer *safeTimer
|
|
}
|
|
|
|
func newTask(f job.FnJob) *task {
|
|
j := job.NewJob(f)
|
|
t := task{
|
|
Job: &j,
|
|
timer: &safeTimer{},
|
|
}
|
|
|
|
return &t
|
|
}
|
|
|
|
func (t *task) abort() {
|
|
if t.timer != nil {
|
|
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()),
|
|
}
|
|
}
|