Skip to content

Add npm run cron:dev to drive the dispatcher locally - #12

Merged
7174Andy merged 1 commit into
mainfrom
local-cron-trigger
Aug 2, 2026
Merged

Add npm run cron:dev to drive the dispatcher locally#12
7174Andy merged 1 commit into
mainfrom
local-cron-trigger

Conversation

@7174Andy

@7174Andy 7174Andy commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Problem

Nothing calls /api/cron/execute on localhost. Production points cron-job.org at the deployed URL and vercel.json declares no crons, so in development a due schedule stays pending indefinitely — scheduledAt is a WHERE filter in getDueScheduleIds, 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 curl loop. This wraps it as npm run cron:dev so it's one command, and so the traps it hides get handled:

  • Loads .env.local ahead of .env, matching Next's precedence and scripts/prisma.mjs. Those files can hold different CRON_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.
  • Ticks before its first sleep, so Ctrl-C after one line gives you a single tick. That's why there's no --once flag.
  • Sequential, not 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_dispatch runs 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 --noEmit clean, npx eslint . clean, npx vitest run 84 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

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>
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gitcron Ready Ready Preview Aug 2, 2026 2:24am

@7174Andy
7174Andy merged commit f858df0 into main Aug 2, 2026
5 checks passed
@7174Andy
7174Andy deleted the local-cron-trigger branch August 2, 2026 02:27
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.

1 participant