Skip to content

Commit 838bd51

Browse files
authored
Issue 778 (#779)
1 parent 40b8570 commit 838bd51

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

job.go

+12
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ type oneTimeJobDefinition struct {
459459
func (o oneTimeJobDefinition) setup(j *internalJob, _ *time.Location, now time.Time) error {
460460
sortedTimes := o.startAt(j)
461461
slices.SortStableFunc(sortedTimes, ascendingTime)
462+
// deduplicate the times
463+
sortedTimes = removeSliceDuplicatesTimeOnSortedSlice(sortedTimes)
462464
// keep only schedules that are in the future
463465
idx, found := slices.BinarySearchFunc(sortedTimes, now, ascendingTime)
464466
if found {
@@ -472,6 +474,16 @@ func (o oneTimeJobDefinition) setup(j *internalJob, _ *time.Location, now time.T
472474
return nil
473475
}
474476

477+
func removeSliceDuplicatesTimeOnSortedSlice(times []time.Time) []time.Time {
478+
ret := make([]time.Time, 0, len(times))
479+
for i, t := range times {
480+
if i == 0 || t != times[i-1] {
481+
ret = append(ret, t)
482+
}
483+
}
484+
return ret
485+
}
486+
475487
// OneTimeJobStartAtOption defines when the one time job is run
476488
type OneTimeJobStartAtOption func(*internalJob) []time.Time
477489

scheduler_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,59 @@ func TestScheduler_AtTimesJob(t *testing.T) {
23252325
},
23262326
},
23272327
},
2328+
2329+
{
2330+
name: "two runs in the future - order is maintained even if times are provided out of order - deduplication",
2331+
atTimes: []time.Time{n.Add(3 * time.Millisecond), n.Add(1 * time.Millisecond), n.Add(1 * time.Millisecond), n.Add(3 * time.Millisecond)},
2332+
fakeClock: clockwork.NewFakeClockAt(n),
2333+
advanceAndAsserts: []func(t *testing.T, j Job, clock clockwork.FakeClock, runs *atomic.Uint32){
2334+
func(t *testing.T, j Job, clock clockwork.FakeClock, runs *atomic.Uint32) {
2335+
require.Equal(t, uint32(0), runs.Load())
2336+
2337+
// last not initialized
2338+
lastRunAt, err := j.LastRun()
2339+
require.NoError(t, err)
2340+
require.Equal(t, time.Time{}, lastRunAt)
2341+
2342+
// next is now
2343+
nextRunAt, err := j.NextRun()
2344+
require.NoError(t, err)
2345+
require.Equal(t, n.Add(1*time.Millisecond), nextRunAt)
2346+
2347+
// advance and eventually run
2348+
clock.Advance(2 * time.Millisecond)
2349+
require.Eventually(t, func() bool {
2350+
return assert.Equal(t, uint32(1), runs.Load())
2351+
}, 3*time.Second, 100*time.Millisecond)
2352+
2353+
// last was run
2354+
lastRunAt, err = j.LastRun()
2355+
require.NoError(t, err)
2356+
require.WithinDuration(t, n.Add(1*time.Millisecond), lastRunAt, 1*time.Millisecond)
2357+
2358+
nextRunAt, err = j.NextRun()
2359+
require.NoError(t, err)
2360+
require.Equal(t, n.Add(3*time.Millisecond), nextRunAt)
2361+
},
2362+
2363+
func(t *testing.T, j Job, clock clockwork.FakeClock, runs *atomic.Uint32) {
2364+
// advance and eventually run
2365+
clock.Advance(2 * time.Millisecond)
2366+
require.Eventually(t, func() bool {
2367+
return assert.Equal(t, uint32(2), runs.Load())
2368+
}, 3*time.Second, 100*time.Millisecond)
2369+
2370+
// last was run
2371+
lastRunAt, err := j.LastRun()
2372+
require.NoError(t, err)
2373+
require.WithinDuration(t, n.Add(3*time.Millisecond), lastRunAt, 1*time.Millisecond)
2374+
2375+
nextRunAt, err := j.NextRun()
2376+
require.NoError(t, err)
2377+
require.Equal(t, time.Time{}, nextRunAt)
2378+
},
2379+
},
2380+
},
23282381
}
23292382

23302383
for _, tt := range tests {

0 commit comments

Comments
 (0)