--- phase: quick-260610-i4x plan: '01' subsystem: broker tags: [scheduler, setInterval, node-cron, fix] dependency_graph: requires: [] provides: [reliable-broker-scheduling] affects: [broker/poller, broker/outboxWorker, broker/reminderScheduler] tech_stack: added: [] patterns: [setInterval-based-scheduling] key_files: created: [] modified: - apps/api/src/broker/poller.ts - apps/api/src/broker/outboxWorker.ts - apps/api/src/broker/reminderScheduler.ts decisions: - 'Use setInterval for broker worker scheduling: node-cron 4.2.1 silently skipped executions in the long-running API process; setInterval is reliable in the same process' metrics: completed: '2026-06-10' --- # Quick Task 260610-i4x: Replace node-cron with setInterval in Broker Workers Summary **One-liner:** Replaced `node-cron` `schedule()` calls with `setInterval` (300 s / 15 s / 60 s) in all three broker worker `start*` functions so scheduled tasks actually fire in the long-running API process. ## Tasks Completed | Task | Name | Commit | Files | | ---- | ------------------------------------------------------------------------------- | ------- | ------------------------------------------------ | | 1 | Swap node-cron schedule() for setInterval in the three worker start\* functions | d9efbc1 | poller.ts, outboxWorker.ts, reminderScheduler.ts | ## Changes Made ### apps/api/src/broker/poller.ts - Removed `import { schedule } from 'node-cron'` - `startBrokerPoller`: `schedule('*/5 * * * *', cb)` → `setInterval(cb, 5 * 60 * 1000)` - Updated file-header and JSDoc comments to reference setInterval and document the WHY ### apps/api/src/broker/outboxWorker.ts - Removed `import { schedule } from 'node-cron'` - `startOutboxWorker`: `schedule('*/15 * * * * *', cb)` → `setInterval(cb, 15 * 1000)` - Updated header comment and scheduler JSDoc ### apps/api/src/broker/reminderScheduler.ts - Removed `import { schedule } from 'node-cron'` - `startReminderScheduler`: `schedule('* * * * *', cb)` → `setInterval(cb, 60 * 1000)` - Updated file-header "Fires every minute" line and scheduler JSDoc Callback bodies (the `.catch`-wrapped `runPoll` / `runOutboxDrain` / `runReminderCheck` calls) are byte-for-byte unchanged. No `.unref()` added — intervals intentionally keep the event loop alive. ## Verification Results - `! grep -rn "import.*node-cron" apps/api/src/broker/`: exits 1 (no matches) — all imports removed - `pnpm --filter @familysync/api typecheck`: **exit 0** — clean - `pnpm --filter @familysync/api exec vitest run tests/broker/`: **8 test files passed, 91 tests passed** ## Deviations from Plan None — plan executed exactly as written. ## Known Stubs None. ## Threat Flags None — no new network surface, auth paths, file access, or schema changes introduced. ## Self-Check: PASSED - [x] `apps/api/src/broker/poller.ts` modified — confirmed - [x] `apps/api/src/broker/outboxWorker.ts` modified — confirmed - [x] `apps/api/src/broker/reminderScheduler.ts` modified — confirmed - [x] Commit d9efbc1 exists on branch gsd/v1.0-milestone - [x] No `import { schedule } from 'node-cron'` in any of the three files - [x] typecheck: exit 0 - [x] broker tests: 8 files / 91 tests — all green