Skip to content

fix(scheduler): prevent NULL next_run_at from permanently dropping schedules - #728

Merged
HongmingWang-Rabbit merged 1 commit into
mainfrom
fix/issue-722-scheduler-null-next-run
Apr 17, 2026
Merged

fix(scheduler): prevent NULL next_run_at from permanently dropping schedules#728
HongmingWang-Rabbit merged 1 commit into
mainfrom
fix/issue-722-scheduler-null-next-run

Conversation

@molecule-ai

@molecule-ai molecule-ai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #722 — three bugs in the scheduler that caused enabled schedules to silently disappear from the fire query (WHERE next_run_at IS NOT NULL AND next_run_at <= now()).

Bug 1 — fireSchedule() + recordSkipped() write NULL on ComputeNextRun error

Root cause: when ComputeNextRun fails (bad cron/tz), nextRunPtr stays nil → UPDATE SET next_run_at = $2 writes NULL → schedule excluded from every future tick.

Fix (scheduler.go): replace next_run_at = $2 with next_run_at = COALESCE($2, next_run_at). When $2 is NULL (error case), the existing DB value is preserved. Error is now logged explicitly.

Bug 2 — org importer silently discards ComputeNextRun error

Root cause: nextRun, _ := scheduler.ComputeNextRun(sched.CronExpr, tz, time.Now()) — error discarded, time.Time{} (zero) passed to INSERT.

Fix (handlers/org.go): surface the error, log it, and continue (skip the INSERT) — consistent with how prompt resolution errors are handled in the same loop.

Bug 3 — no startup repair for already-NULL'd schedules

Root cause: schedules broken by the pre-fix binary stay broken forever even after patching.

Fix (scheduler.go): Start() calls repairNullNextRunAt() once on boot — queries enabled = true AND next_run_at IS NULL, recomputes via ComputeNextRun, and UPDATEs each row. Logs count of repaired/skipped schedules.

Tests added (all pass)

Test Covers
TestFireSchedule_ComputeNextRunError Bug 1: UPDATE fires with COALESCE when ComputeNextRun fails
TestRecordSkipped_ComputeNextRunError Bug 1: same invariant on the skipped path
TestRepairNullNextRunAt_RepairsRows Bug 3: startup repair SELECTs NULL rows and UPDATEs each
TestRepairNullNextRunAt_DBError_NoPanic Bug 3: DB error in SELECT is logged, no crash
TestOrgImport_ScheduleComputeError Bug 2: confirms ComputeNextRun returns error for invalid inputs (skip path reachable)

Test output

ok  github.com/Molecule-AI/molecule-monorepo/platform/internal/scheduler  (14/14 tests pass)
ok  github.com/Molecule-AI/molecule-monorepo/platform/internal/handlers   (all pass)
ok  all packages — go test ./... -count=1

Test plan

  • go build ./... — clean
  • go test ./... -count=1 — all packages pass
  • Manual: create a schedule with a valid cron expression, binary-patch to old code to NULL it, restart new binary → verify startup repair log line and schedule fires again
  • Manual: org import with an invalid cron expression in org.yaml → verify schedule is skipped with log, other schedules still created

🤖 Generated with Claude Code

…hedules (#722)

Three bugs caused enabled schedules to silently disappear from the fire query
(which requires next_run_at IS NOT NULL AND next_run_at <= now()):

Bug 1 - fireSchedule() and recordSkipped(): when ComputeNextRun returned an
error, nextRunPtr stayed nil and UPDATE SET next_run_at = $2 wrote NULL.
Fix: change to COALESCE($2, next_run_at) so the existing DB value is preserved
when $2 is NULL, and log the error explicitly.

Bug 2 - org importer (handlers/org.go): nextRun, _ := ComputeNextRun(...)
silently discarded the error. A bad cron expression would pass time.Time{}
(zero value) to the INSERT. Fix: surface the error, log it, and skip the
schedule INSERT via continue.

Bug 3 - no startup repair: schedules already NULL'd by the pre-fix binary
would never recover. Fix: Start() now calls repairNullNextRunAt() once on
boot, recomputing next_run_at for every enabled schedule with a NULL value.

Tests: TestFireSchedule_ComputeNextRunError, TestRecordSkipped_ComputeNextRunError,
TestRepairNullNextRunAt_RepairsRows, TestRepairNullNextRunAt_DBError_NoPanic,
TestOrgImport_ScheduleComputeError (all pass).

Fixes #722

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@HongmingWang-Rabbit
HongmingWang-Rabbit merged commit ae7df68 into main Apr 17, 2026
6 checks passed
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the fix/issue-722-scheduler-null-next-run branch April 17, 2026 13:47
molecule-ai Bot pushed a commit that referenced this pull request Apr 21, 2026
…-next-run

fix(scheduler): prevent NULL next_run_at from permanently dropping schedules
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: scheduler sets next_run_at=NULL on ComputeNextRun failure, permanently silencing schedule

1 participant