Jobs & scheduling (registry, runner, platform-owned cadence)
Generated from
mcp/patterns.registry.json— do not edit by hand; change the registry and runbun run patterns:build.
Category: Jobs & Scheduling · Tier: deep · Risk: medium — touches deploy config and background execution
A slug→execute job registry with a unified runner; cadence lives entirely in platform config (Vercel cron vs container setInterval), so switching hosts needs zero job-code change.
When to use: Use for any recurring or background work — the registry/runner split keeps jobs testable and host-portable.
Docs
- docs/blueprint/architecture/jobs.md — The full pattern including cadence ownership (GitHub · GitLab)
Code
src/lib/server/jobs/index.ts— Registry: slug → execute function, nothing more (GitHub · GitLab)src/lib/server/jobs/runner.ts— runJob() unified runner (GitHub · GitLab)src/lib/server/jobs/scheduler.ts— Container-mode persistent setInterval scheduler (GitHub · GitLab)src/routes/api/cron/[job]/+server.ts— Dynamic Vercel cron entry (GitHub · GitLab)vercel.json— Where cron schedules live (GitHub · GitLab)
Tests
src/lib/server/jobs/retention.test.ts(GitHub · GitLab)src/lib/server/jobs/dbops-refresh.test.ts(GitHub · GitLab)
Proof
Invariants
- The registry maps a slug to an execute function — nothing more; cadence lives in platform config, the registry has no schedule field.
- Every registered job needs a vercel.json cron entry — a slug with no entry never fires.
- Cron delivery is at-least-once — jobs must be idempotent.
Emulation notes
- Jobs are a client of domain modules (multi-client core): a job body should call the same domain functions the UI calls.
- Vercel Hobby tier rejects sub-daily cron schedules at deploy time — plan cadence accordingly.
Depends on
Machine-readable record: jobs-scheduler in mcp/patterns.registry.json.