Add npm run cron:dev to drive the dispatcher locally - #12
Merged
Conversation
Nothing calls /api/cron/execute on localhost. Production points cron-job.org
at the deployed URL and vercel.json declares no crons, so a due schedule stays
"pending" indefinitely in development - scheduledAt is a WHERE filter in
getDueScheduleIds, not a timer. This reads as a bug ("the job never fired")
when it is really just a missing caller.
The README already documented a hand-rolled curl loop for this. Wrap it as a
script so it is one command, and so the two traps it hides are handled:
- It loads .env.local ahead of .env, matching Next's precedence. Those files
can hold different CRON_SECRETs, and a call made with the wrong one returns
401 - which again looks like "the job never fired". The script names that
cause explicitly on a 401 rather than printing a bare status code.
- It ticks before its first sleep, so Ctrl-C after one line is a single tick.
Sequential rather than setInterval so a slow tick cannot overlap itself, and
it keeps going when the dev server is down or restarting.
Also corrects the README, which promised raw JSON the script does not print
and described calling the endpoint repeatedly by hand.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Nothing calls
/api/cron/executeon localhost. Production points cron-job.org at the deployed URL andvercel.jsondeclares no crons, so in development a due schedule stayspendingindefinitely —scheduledAtis aWHEREfilter ingetDueScheduleIds, not a timer.This presents as a bug ("my scheduled job never fired") when it's really a missing caller. I lost time to exactly this before tracing it.
Approach
The README already documented a hand-rolled
curlloop. This wraps it asnpm run cron:devso it's one command, and so the traps it hides get handled:.env.localahead of.env, matching Next's precedence andscripts/prisma.mjs. Those files can hold differentCRON_SECRETs, and calling with the wrong one returns 401 — which also looks like "the job never fired". On a 401 the script names that cause instead of printing a bare status code.--onceflag.setInterval, so a slow tick can't overlap itself. Keeps going when the dev server is down or mid-restart.Also corrects the README, which promised raw JSON the script doesn't print and described calling the endpoint repeatedly by hand.
Safety
This calls the real dispatcher — it dispatches real
workflow_dispatchruns against real repositories. It is not a simulation. The script says so on startup and the README says so twice, because the failure mode (a surprise run against a production repo) is unpleasant.Testing
npx tsc --noEmitclean,npx eslint .clean,npx vitest run84 passing.Exercised the 401 path, the unreachable-server path, and loop iteration (via
CRON_DEV_INTERVAL_MS=200). The success path is untested — any successful call dispatches a real workflow run, so I didn't trigger one.🤖 Generated with Claude Code