Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
8.6 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260610-i4x | 01 | execute | 1 |
|
true |
|
|
Purpose: node-cron 4.2.1 silently skips scheduled executions in the long-lived server
process — the orchestrator proved this live against the running prod container (continuous
[NODE-CRON][WARN] missed execution at every tick while CPU sat at 0.15%; a plain
setInterval(…,1000) in the SAME container fired 8/8 ticks, and a FRESH node-cron process
fired 8/8 — only the long-lived process misbehaves). Net effect: the CalDAV poller, the
outbox drain, and the reminder scan never fire on schedule. They only ran when triggered
manually during debugging.
Output: Three worker files where startBrokerPoller, startOutboxWorker, and
startReminderScheduler schedule their existing callbacks with setInterval at the same
intervals, with the now-unused node-cron import removed and stale doc comments updated.
<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md </execution_context>
@./CLAUDE.mdThe three worker files — only the start* functions and their doc comments change.
Do NOT modify runPoll / runOutboxDrain / runReminderCheck logic.
@apps/api/src/broker/poller.ts @apps/api/src/broker/outboxWorker.ts @apps/api/src/broker/reminderScheduler.ts
Task 1: Swap node-cron schedule() for setInterval in the three worker start* functions apps/api/src/broker/poller.ts, apps/api/src/broker/outboxWorker.ts, apps/api/src/broker/reminderScheduler.ts In each of the three files, replace the node-cron scheduling call inside the start* function with a setInterval call, keeping the callback body EXACTLY as written (it already wraps the run function in `.catch(...)`). Then remove the now-unused `import { schedule } from 'node-cron'` line from each file. Do NOT touch runPoll / runOutboxDrain / runReminderCheck, the constants, helpers, or any other code. Do NOT touch index.ts, package.json, or the lockfile — the start* function names and signatures are unchanged so index.ts keeps working as-is.Exact mapping (interval in ms = the cron cadence; setInterval fires after the first interval, same first-run timing as the old cron — do NOT add an immediate kick, that is out of scope):
-
poller.ts
startBrokerPoller: changeschedule('*/5 * * * *', () => { ... })tosetInterval(() => { ... }, 5 * 60 * 1000)— keep the same arrow-function callback body (therunPoll().catch(...)block). -
outboxWorker.ts
startOutboxWorker: changeschedule('*/15 * * * * *', () => { ... })tosetInterval(() => { ... }, 15 * 1000)— keep the samerunOutboxDrain().catch(...)body. -
reminderScheduler.ts
startReminderScheduler: changeschedule('* * * * *', () => { ... })tosetInterval(() => { ... }, 60 * 1000)— keep the samerunReminderCheck().catch(...)body.
Do NOT call .unref() on the returned Timer — we WANT the interval to keep the event loop
alive (same effect as cron kept the process alive). Storing the returned Timer handle in a
module-level variable is acceptable if cleaner, but not required — fire-and-forget matches the
current pattern (the workers run for the process lifetime).
Update the now-stale doc comments that reference node-cron so they describe setInterval, keeping the WHY. Specifically:
- poller.ts: the file-header line "runs every 5 minutes via node-cron", the "startBrokerPoller wraps it in node-cron's 5-minute schedule." line, the "Source: https://github.com/node-cron/node-cron ..." source line, and the "Starts the 5-minute background polling schedule." block.
- outboxWorker.ts: "startOutboxWorker wraps it in a 15-second node-cron schedule." and the "Source: https://github.com/node-cron/node-cron (v4 stable)" line, plus the "Starts the 15-second background outbox drain schedule." block.
- reminderScheduler.ts: the file-header "Fires every minute via node-cron." line and the
"Start the 1-minute reminder scan schedule." block comment ("keeps the cron out of the test
process" → setInterval phrasing).
Each updated comment must briefly state the WHY (node-cron 4.2.1 skipped scheduled executions
in the long-running server process, so scheduling uses setInterval instead). Keep edits brief —
do not rewrite the surrounding decision/threat-mitigation prose. Leave the
node-crondependency in package.json (now unused, harmless); it is removable later but removing it now risks lockfile drift and is out of scope for this tight change. cd /home/luc/Projects/familysync && ! grep -rn "node-cron" apps/api/src/broker/poller.ts apps/api/src/broker/outboxWorker.ts apps/api/src/broker/reminderScheduler.ts | grep -v '^\s*[0-9]*:.//' ; grep -c "setInterval" apps/api/src/broker/poller.ts apps/api/src/broker/outboxWorker.ts apps/api/src/broker/reminderScheduler.ts cd /home/luc/Projects/familysync && pnpm --filter @familysync/api typecheck cd /home/luc/Projects/familysync && pnpm --filter @familysync/api exec vitest run tests/broker/ All three files import setInterval-based scheduling with no remainingimport { schedule } from 'node-cron'; each start function calls setInterval at the correct interval (poller 300000 ms, outbox 15000 ms, reminder 60000 ms) with its original callback body intact;pnpm --filter @familysync/api typecheckexits 0; andpnpm --filter @familysync/api exec vitest run tests/broker/reports all broker tests green (runPoll / runOutboxDrain / runReminderCheck behavior unchanged).
<success_criteria> The three background workers schedule their callbacks via setInterval at the original intervals (5 min / 15 s / 1 min), node-cron is no longer imported in src/broker, the apps/api typecheck is clean, and the broker unit tests still pass — so in the long-running API process the poller, outbox drain, and reminder scan will now actually fire on schedule. </success_criteria>
Create `.planning/quick/260610-i4x-replace-node-cron-with-setinterval-in-ba/260610-i4x-SUMMARY.md` when done.