rework locker + fix job state + fix graceful stop

This commit is contained in:
rmanach 2024-09-24 11:55:33 +02:00
parent 4da553d156
commit 0cd4f264a3
2 changed files with 67 additions and 33 deletions

View File

@ -59,7 +59,6 @@ type JobDetails struct {
Err string `json:"error"` Err string `json:"error"`
} }
// TODO(rmanach): add priority level
type Job struct { type Job struct {
l sync.RWMutex l sync.RWMutex
id uuid.UUID id uuid.UUID
@ -130,7 +129,10 @@ func (j *Job) setFail(err error) {
now := time.Now().UTC() now := time.Now().UTC()
j.updatedAt = &now j.updatedAt = &now
if j.state != Abort {
j.state = Failed j.state = Failed
}
j.err = err j.err = err
} }

View File

@ -29,18 +29,42 @@ const (
High High
) )
type jobSlot struct { type JobSlotDetails struct {
*job.Job job.JobDetails
row int Attempts int `json:"attempts"`
col int
} }
func newJobSlot(task job.FnJob, row, col int) jobSlot { type jobSlot struct {
j := job.NewJob(task) l sync.RWMutex
job.Job
slot int
attempts int
// priority Priority
}
func newJobSlot(task job.FnJob, slot int) jobSlot {
return jobSlot{ return jobSlot{
Job: &j, Job: job.NewJob(task),
row: row, slot: slot,
col: col, }
}
func (j *jobSlot) run(ctx context.Context) {
j.l.Lock()
defer j.l.Unlock()
j.attempts += 1
j.Job.Run(ctx)
}
func (j *jobSlot) getDetails() JobSlotDetails {
j.l.RLock()
defer j.l.RUnlock()
return JobSlotDetails{
JobDetails: j.IntoDetails(),
Attempts: j.attempts,
} }
} }
@ -95,22 +119,22 @@ func (c *SchedulerCycle) Done() <-chan struct{} {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
<-c.ctx.Done() <-c.ctx.Done()
c.wg.Done() c.wg.Wait()
done <- struct{}{} done <- struct{}{}
}() }()
return done return done
} }
func (c *SchedulerCycle) Len() int { func (c *SchedulerCycle) Len() int {
c.l.Lock() c.l.RLock()
defer c.l.Unlock() defer c.l.RUnlock()
return len(c.jobs) return len(c.jobs)
} }
func (c *SchedulerCycle) HasAllJobsDone() bool { func (c *SchedulerCycle) HasAllJobsDone() bool {
c.l.Lock() c.l.RLock()
defer c.l.Unlock() defer c.l.RUnlock()
for _, j := range c.jobs { for _, j := range c.jobs {
if j.GetState() == job.Pending || j.GetState() == job.Running { if j.GetState() == job.Pending || j.GetState() == job.Running {
@ -121,13 +145,13 @@ func (c *SchedulerCycle) HasAllJobsDone() bool {
return true return true
} }
func (c *SchedulerCycle) GetJobsDetails() []job.JobDetails { func (c *SchedulerCycle) GetJobsDetails() []JobSlotDetails {
c.l.Lock() c.l.RLock()
defer c.l.Unlock() defer c.l.RUnlock()
details := []job.JobDetails{} details := []JobSlotDetails{}
for _, j := range c.jobs { for _, j := range c.jobs {
details = append(details, j.IntoDetails()) details = append(details, j.getDetails())
} }
return details return details
@ -135,6 +159,12 @@ func (c *SchedulerCycle) GetJobsDetails() []job.JobDetails {
// Delay builds a job and add it to the scheduler engine. // Delay builds a job and add it to the scheduler engine.
func (c *SchedulerCycle) Delay(fnJob job.FnJob) uuid.UUID { func (c *SchedulerCycle) Delay(fnJob job.FnJob) uuid.UUID {
select {
case <-c.Done():
log.Error().Msg("context done unable to add new job")
default:
}
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
@ -143,7 +173,7 @@ func (c *SchedulerCycle) Delay(fnJob job.FnJob) uuid.UUID {
nextSlot = 0 nextSlot = 0
} }
j := newJobSlot(fnJob, nextSlot, len(c.slots[nextSlot])) j := newJobSlot(fnJob, nextSlot)
c.slots[nextSlot] = append(c.slots[nextSlot], &j) c.slots[nextSlot] = append(c.slots[nextSlot], &j)
c.jobs[j.GetID()] = &j c.jobs[j.GetID()] = &j
@ -165,18 +195,20 @@ func (c *SchedulerCycle) Abort(id uuid.UUID) bool {
} }
// GetJobDetails returns the job details by . // GetJobDetails returns the job details by .
func (c *SchedulerCycle) GetJobDetails(id uuid.UUID) job.JobDetails { func (c *SchedulerCycle) GetJobDetails(id uuid.UUID) JobSlotDetails {
c.l.Lock() c.l.RLock()
defer c.l.Unlock() defer c.l.RUnlock()
j, ok := c.jobs[id] j, ok := c.jobs[id]
if !ok { if !ok {
return job.JobDetails{ return JobSlotDetails{
State: job.Unknown.String(), JobDetails: job.JobDetails{
State: job.UnknownState,
},
} }
} }
return j.IntoDetails() return j.getDetails()
} }
// Display outputs earch interval the scheduler state. // Display outputs earch interval the scheduler state.
@ -285,11 +317,11 @@ func (c *SchedulerCycle) getCurrentSlotJobs() (int, []*jobSlot) {
} }
// updateSlot add a job to the slot where it was before. // updateSlot add a job to the slot where it was before.
func (c *SchedulerCycle) updateSlot(row int, j *jobSlot) { func (c *SchedulerCycle) updateSlot(slot int, j *jobSlot) {
c.l.Lock() c.l.Lock()
defer c.l.Unlock() defer c.l.Unlock()
c.slots[row] = append(c.slots[row], j) c.slots[slot] = append(c.slots[slot], j)
} }
// updateCurrentSlot add a job to the current slot. // updateCurrentSlot add a job to the current slot.
@ -320,7 +352,7 @@ func (c *SchedulerCycle) incr() {
// It all the workers are busy, the jobs are re-schedule in the same slot // It all the workers are busy, the jobs are re-schedule in the same slot
// to be executed in the next cycle. // to be executed in the next cycle.
func (c *SchedulerCycle) dispatch() { func (c *SchedulerCycle) dispatch() {
row, jobs := c.getCurrentSlotJobs() slot, jobs := c.getCurrentSlotJobs()
for _, j := range jobs { for _, j := range jobs {
if j.GetState() == job.Abort { if j.GetState() == job.Abort {
continue continue
@ -330,7 +362,7 @@ func (c *SchedulerCycle) dispatch() {
case c.chJobs <- j: case c.chJobs <- j:
default: default:
log.Warn().Msg("unable to put job in workers, trying next cycle") log.Warn().Msg("unable to put job in workers, trying next cycle")
c.updateSlot(row, j) c.updateSlot(slot, j)
} }
} }
} }
@ -362,7 +394,7 @@ func (c *SchedulerCycle) workers() {
} }
func (c *SchedulerCycle) executeJob(j *jobSlot, fnFallBack func(*jobSlot)) { func (c *SchedulerCycle) executeJob(j *jobSlot, fnFallBack func(*jobSlot)) {
j.Run(c.ctx) j.run(c.ctx)
if j.GetState() == job.Pending { if j.GetState() == job.Pending {
fnFallBack(j) fnFallBack(j)
} }