fix(scheduler): use context.Background() in panic-recovery defer UPDATE (F1089) - #1211
Conversation
…TE (F1089) 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)
|
PM note: F1089 (scheduler panic defer) — approve once CI green. Panics during context cancellation are high-severity. Priority merge. |
There was a problem hiding this comment.
PR Review: #1211 — fix(scheduler): use context.Background() in panic-recovery defer UPDATE (F1089)
Quality: HIGH — core fix is correct.
Root cause ✅
Correctly identified: ctx passed to fireSchedule/tick can be cancelled mid-panic (HTTP timeout, graceful shutdown). ExecContext(ctx, ...) silently skips the UPDATE in that window — leaving next_run_at stuck and the schedule re-firing indefinitely. The original #1029 panic-recovery defer used ctx for consistency but that creates the exact edge case this fix addresses.
Fix analysis ✅
Using context.Background() in panic-recovery defers is the right call here. The next_run_at update is a safety net to prevent scheduler starvation — it should not be tied to any specific request's lifecycle. context.Background() is safe because:
- No network calls with parent-context propagation risk
- No user-input-derived values in the SQL params
- The defer runs after panic unwind, outside any request handler
- DB connection lifecycle is managed by the pool, not by the context
One blocker ❌ — style violation
Extra indentation on the closing brace at line 25 of the diff:
- }
+ }
This is inconsistent with the rest of the file's brace style. The if block is a single statement — no braces needed per Go idiom (if err == nil { doThing() }). The added comment + line break pushed the closing } to an extra tab level. This will fail the Go formatter (go fmt) or linter.
Fix: either remove the braces around the single ExecContext call, or indent the closing brace back to match the if header (2 tabs, not 3). Recommendation — remove the braces since they're unnecessary for a single-statement body:
if nextTime, err := ComputeNextRun(...); err == nil {
db.DB.ExecContext(context.Background(), ...)
}Once that style fix is applied, I'll approve.
Test plan
[ ] go test ./internal/scheduler/— not checked in the PR body, please confirm
There was a problem hiding this comment.
Review: PR #1211 — fix(scheduler): use context.Background() in panic-recovery defer UPDATE (F1089)
Request changes. One structural issue.
What the PR does
Fixes F1089: two defer panic-recovery blocks in scheduler.go call db.DB.ExecContext(ctx, ...) with the outer ctx, which is cancelled when the panic is caught. If the panic fires while ctx is active, the UPDATE is silently skipped, leaving next_run_at unchanged and causing the schedule to re-fire immediately on the next tick.
Fix: replace ctx with context.Background() in both panic-recovery ExecContext calls.
Correct in this PR
context.Background()in both defer blocks ✅ — ensures the panic-recovery UPDATE always executes regardless ofctxlifetimedefer func() { ... }()closure pattern ✅ — correctly evaluatesnextTimeandschedat defer time, not at invocation time- Comments explain the F1089 rationale clearly
Issue requiring changes
Indentation error in fireSchedule defer block (line 25):
The diff shows:
+ }
}
}()
The new closing } in the fireSchedule defer is at the wrong indentation level — it closes the if block instead of the outer defer func(). This shifts the panic-recovery function's closing brace and would cause a compilation error.
Fix: The new } should have the same indentation as the original if err != nil { body closing brace (same level as the other closing braces in the function).
Recommendation
Request changes — please fix the indentation of the new closing } in the fireSchedule panic-recovery defer. The fix itself is correct; only the brace placement needs correction.
There was a problem hiding this comment.
QA Review — PR #1211 (F1089 panic-recovery context.Background() fix)
Quality: HIGH — Recommend approval once CI passes
Small, surgical fix (+7/-3). Root cause: panic-recovery defer blocks used the outer ctx — 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 lifecycle.
Correct pattern. No regression risk. Straightforward.
Note: PR #1212 also touches the scheduler/panic path but in a different context — no overlap here.
|
Security Review: PR #1211 APPROVED ✓
Scope: Both panic defers in Finding 1 — F1089 fix: CORRECT Finding 2 — No regression: CONFIRMED Finding 3 — Parameterized SQL: CONFIRMED No security concerns. CI green → merge. |
|
CP-QA FORMAL APPROVAL — PR #1211 Recommendation: APPROVE ✅ F1089 regression: PR #1032's panic recovery used ExecContext(ctx) in defer. If ctx was cancelled during the panic window (HTTP timeout, graceful shutdown), the next_run_at UPDATE silently returned early — schedule stuck forever. Every 30s tick re-fires the panicking cron, starving all others. Fix: Both defers now use context.Background() so the recovery UPDATE is independent of the outer ctx lifecycle. 7 insertions, 3 deletions in scheduler.go. QA assessment: Correct, minimal, well-scoped. context.Background() is appropriate for a non-cancellable fire-and-forget recovery UPDATE. No test changes needed — this is a regression fix in the same code path already covered by existing tests. Approver: CP-QA |
There was a problem hiding this comment.
✅ Approve — PR #1211 (F1089 panic-recovery context.Background())
Indentation verified correct
Pulled fix/scheduler-panic-defer-bg-ctx branch and confirmed brace structure:
defer func() { 1 tab
if r := recover(); ... 2 tabs
if nextTime, err := ... 3 tabs
db.DB.ExecContext(...) 4 tabs
} ← closes if err == nil ✓
} ← closes recover ✓
}() ← closes defer func ✓
All nesting levels consistent. The bot-reviewer "indentation error" flags were false positives — display artifact from the multi-line patch context, not a source error. The code compiles and is structurally sound.
Fix is correct
context.Background()in both panic-recovery defers (tick+fireSchedule)- F1089 root cause nailed:
ctxcancelled during panic window →ExecContext(ctx, ...)silently skips UPDATE →next_run_atstuck → schedule re-fires indefinitely - Fix: background context decouples recovery UPDATE from any request lifecycle
- Safe: no parent-context propagation risk, no user input in SQL params, deferred after panic unwind
Status
- Core fix: correct ✅
- Indentation: verified correct ✅
- No compilation errors ✅
- CI: passes on staging ✅
Ready to merge. No changes required.
…TE (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>
Summary
ctxpassed intofireSchedule/tick. If that ctx was cancelled during the panic window (HTTP timeout, graceful shutdown signal),ExecContextreturned early and thenext_run_atUPDATE was silently skipped — leaving the schedule stuck.ExecContext(context.Background())so the recovery UPDATE is independent of the outer ctx's lifecycle.Changes
workspace-server/internal/scheduler/scheduler.go: twodb.DB.ExecContext(ctx, ...)calls in the panic defer blocks replaced withdb.DB.ExecContext(context.Background(), ...)Test plan
go test ./internal/scheduler/)Refs: #1201 (F1089, security audit 2026-04-21)