fix(scheduler): use context.Background() in panic-recovery defer UPDATE (F1089) (#1211)

F1089: PR #1032's panic-recovery defers used the outer `ctx` passed into
fireSchedule/tick. If that ctx was cancelled during the panic window
(HTTP timeout, graceful shutdown), ExecContext returned early and the
next_run_at UPDATE was silently skipped — leaving the schedule stuck.

Fix: both panic defers now call ExecContext(context.Background()) so the
recovery UPDATE is independent of the outer ctx's lifecycle.

Refs: #1201 (F1089, security audit 2026-04-21)

Co-authored-by: Molecule AI CP-BE <cp-be@agents.moleculesai.app>
This commit is contained in:
molecule-ai[bot] 2026-04-21 02:08:00 +00:00 committed by GitHub
parent 0cb7445502
commit 09b5a444d3

View File

@ -215,7 +215,9 @@ func (s *Scheduler) tick(ctx context.Context) {
// Always advance next_run_at even on panic so the schedule doesn't get
// stuck re-firing the same panicking schedule indefinitely (#1029).
if nextTime, err := ComputeNextRun(s2.CronExpr, s2.Timezone, time.Now()); err == nil {
db.DB.ExecContext(ctx, `UPDATE workspace_schedules SET next_run_at=$1, updated_at=now() WHERE id=$2`, nextTime, s2.ID)
// F1089: use context.Background() so the panic-recovery UPDATE is not
// silently skipped if the outer ctx was cancelled during the panic window.
db.DB.ExecContext(context.Background(), `UPDATE workspace_schedules SET next_run_at=$1, updated_at=now() WHERE id=$2`, nextTime, s2.ID)
}
}
}()
@ -246,8 +248,10 @@ func (s *Scheduler) fireSchedule(ctx context.Context, sched scheduleRow) {
// Always advance next_run_at even on panic so the schedule doesn't get
// stuck re-firing the same panicking schedule indefinitely (#1029).
if nextTime, err := ComputeNextRun(sched.CronExpr, sched.Timezone, time.Now()); err == nil {
db.DB.ExecContext(ctx, `UPDATE workspace_schedules SET next_run_at=$1, updated_at=now() WHERE id=$2`, nextTime, sched.ID)
}
// F1089: use context.Background() so the panic-recovery UPDATE is not
// silently skipped if the outer ctx was cancelled during the panic window.
db.DB.ExecContext(context.Background(), `UPDATE workspace_schedules SET next_run_at=$1, updated_at=now() WHERE id=$2`, nextTime, sched.ID)
}
}
}()