fix(cron): improve wake channel handling and enhance concurrency in tests
This commit is contained in:
parent
991c7845d5
commit
5513de0b98
2 changed files with 22 additions and 10 deletions
|
|
@ -74,6 +74,7 @@ func NewCronService(storePath string, onJob JobHandler) *CronService {
|
||||||
storePath: storePath,
|
storePath: storePath,
|
||||||
onJob: onJob,
|
onJob: onJob,
|
||||||
gronx: gronx.New(),
|
gronx: gronx.New(),
|
||||||
|
wakeChan: make(chan struct{}),
|
||||||
}
|
}
|
||||||
// Initialize and load store on creation
|
// Initialize and load store on creation
|
||||||
cs.loadStore()
|
cs.loadStore()
|
||||||
|
|
@ -98,7 +99,9 @@ func (cs *CronService) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
cs.stopChan = make(chan struct{})
|
cs.stopChan = make(chan struct{})
|
||||||
cs.wakeChan = make(chan struct{})
|
if cs.wakeChan == nil {
|
||||||
|
cs.wakeChan = make(chan struct{})
|
||||||
|
}
|
||||||
cs.running = true
|
cs.running = true
|
||||||
go cs.runLoop(cs.stopChan)
|
go cs.runLoop(cs.stopChan)
|
||||||
|
|
||||||
|
|
@ -332,6 +335,15 @@ func (cs *CronService) computeNextRun(schedule *CronSchedule, nowMS int64) *int6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wake up the loop to re-evaluate next wake time immediately (e.g. after add/update/remove jobs)
|
||||||
|
func (cs *CronService) notify() {
|
||||||
|
select {
|
||||||
|
case cs.wakeChan <- struct{}{}:
|
||||||
|
default:
|
||||||
|
// if the channel is full, it means the loop will wake up soon anyway, so we can skip sending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cs *CronService) recomputeNextRuns() {
|
func (cs *CronService) recomputeNextRuns() {
|
||||||
now := time.Now().UnixMilli()
|
now := time.Now().UnixMilli()
|
||||||
for i := range cs.store.Jobs {
|
for i := range cs.store.Jobs {
|
||||||
|
|
@ -433,10 +445,7 @@ func (cs *CronService) AddJob(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
cs.notify()
|
||||||
case cs.wakeChan <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return &job, nil
|
return &job, nil
|
||||||
}
|
}
|
||||||
|
|
@ -450,10 +459,7 @@ func (cs *CronService) UpdateJob(job *CronJob) error {
|
||||||
cs.store.Jobs[i] = *job
|
cs.store.Jobs[i] = *job
|
||||||
cs.store.Jobs[i].UpdatedAtMS = time.Now().UnixMilli()
|
cs.store.Jobs[i].UpdatedAtMS = time.Now().UnixMilli()
|
||||||
|
|
||||||
select {
|
cs.notify()
|
||||||
case cs.wakeChan <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return cs.saveStoreUnsafe()
|
return cs.saveStoreUnsafe()
|
||||||
}
|
}
|
||||||
|
|
@ -485,6 +491,8 @@ func (cs *CronService) removeJobUnsafe(jobID string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cs.notify()
|
||||||
|
|
||||||
return removed
|
return removed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,6 +515,9 @@ func (cs *CronService) EnableJob(jobID string, enabled bool) *CronJob {
|
||||||
if err := cs.saveStoreUnsafe(); err != nil {
|
if err := cs.saveStoreUnsafe(); err != nil {
|
||||||
log.Printf("[cron] failed to save store after enable: %v", err)
|
log.Printf("[cron] failed to save store after enable: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cs.notify()
|
||||||
|
|
||||||
return job
|
return job
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ func TestCronService_ConcurrentAccess(t *testing.T) {
|
||||||
for j := range iterations {
|
for j := range iterations {
|
||||||
at := time.Now().Add(time.Hour).UnixMilli()
|
at := time.Now().Add(time.Hour).UnixMilli()
|
||||||
cs.AddJob(fmt.Sprintf("Job-%d-%d", id, j), CronSchedule{Kind: "at", AtMS: &at}, "", false, "", "")
|
cs.AddJob(fmt.Sprintf("Job-%d-%d", id, j), CronSchedule{Kind: "at", AtMS: &at}, "", false, "", "")
|
||||||
|
time.Sleep(100 * time.Microsecond)
|
||||||
}
|
}
|
||||||
}(i)
|
}(i)
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +228,7 @@ func TestCronService_ConcurrentAccess(t *testing.T) {
|
||||||
if len(jobs) > 0 {
|
if len(jobs) > 0 {
|
||||||
cs.EnableJob(jobs[0].ID, j%2 == 0)
|
cs.EnableJob(jobs[0].ID, j%2 == 0)
|
||||||
}
|
}
|
||||||
time.Sleep(1 * time.Millisecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue