diff --git a/internal/manager/persistence/workers.go b/internal/manager/persistence/workers.go index eb20c243..2f44632b 100644 --- a/internal/manager/persistence/workers.go +++ b/internal/manager/persistence/workers.go @@ -33,6 +33,10 @@ type Worker struct { } func (w *Worker) Identifier() string { + // Avoid a panic when worker.Identifier() is called on a nil pointer. + if w == nil { + return "-nil worker-" + } return fmt.Sprintf("%s (%s)", w.Name, w.UUID) } diff --git a/internal/manager/sleep_scheduler/sleep_scheduler.go b/internal/manager/sleep_scheduler/sleep_scheduler.go index aee2891b..efd3228d 100644 --- a/internal/manager/sleep_scheduler/sleep_scheduler.go +++ b/internal/manager/sleep_scheduler/sleep_scheduler.go @@ -4,6 +4,7 @@ package sleep_scheduler import ( "context" + "errors" "fmt" "time" @@ -200,7 +201,12 @@ func (ss *SleepScheduler) CheckSchedules(ctx context.Context) { func (ss *SleepScheduler) checkSchedule(ctx context.Context, schedule *persistence.SleepSchedule) { // Compute the next time to check. schedule.NextCheck = ss.calculateNextCheck(schedule) - if err := ss.persist.SetWorkerSleepScheduleNextCheck(ctx, schedule); err != nil { + err := ss.persist.SetWorkerSleepScheduleNextCheck(ctx, schedule) + switch { + case errors.Is(ctx.Err(), context.Canceled): + // Manager is shutting down, this is fine. + return + case err != nil: log.Error(). Err(err). Str("worker", schedule.Worker.Identifier()). @@ -209,12 +215,15 @@ func (ss *SleepScheduler) checkSchedule(ctx context.Context, schedule *persisten } // Apply the schedule to the worker. - if err := ss.ApplySleepSchedule(ctx, schedule); err != nil { + err = ss.ApplySleepSchedule(ctx, schedule) + switch { + case errors.Is(ctx.Err(), context.Canceled): + // Manager is shutting down, this is fine. + case err != nil: log.Error(). Err(err). Str("worker", schedule.Worker.Identifier()). Msg("sleep scheduler: error applying worker's sleep schedule") - return } } diff --git a/internal/manager/sleep_scheduler/sleep_scheduler_test.go b/internal/manager/sleep_scheduler/sleep_scheduler_test.go index 166394e5..65dfe3d8 100644 --- a/internal/manager/sleep_scheduler/sleep_scheduler_test.go +++ b/internal/manager/sleep_scheduler/sleep_scheduler_test.go @@ -95,6 +95,25 @@ func TestSetScheduleSwappedStartEnd(t *testing.T) { assert.NoError(t, err) } +// Test that a sleep check that happens at shutdown of the Manager doesn't cause any panics. +func TestCheckSleepScheduleAtShutdown(t *testing.T) { + ss, mocks, _ := testFixtures(t) + + sched := persistence.SleepSchedule{ + IsActive: true, + DaysOfWeek: "mo tu we", + StartTime: mkToD(18, 0), + EndTime: mkToD(9, 0), + Worker: nil, + } + + // Cancel the context to mimick the Manager shutting down. + ctx, cancel := context.WithCancel(context.Background()) + cancel() + mocks.persist.EXPECT().SetWorkerSleepScheduleNextCheck(ctx, &sched).Return(context.Canceled) + ss.checkSchedule(ctx, &sched) +} + func TestApplySleepSchedule(t *testing.T) { ss, mocks, ctx := testFixtures(t)