In-process cron for Bun and Node.
Give a job a name, a schedule and a function. Cronbake runs it to the second, won’t start it twice if the last run is still going, and keeps a record of what happened.
bun add cronbake- Second
- 0at :00
- Minute
- 30at :30
- Hour
- 909:xx
- Day
- *every day
- Month
- *every month
- Weekday
- 1-5Mon to Fri
Next run in--:--:--Your local time
Upcoming runs
What it looks like
- Six fields or a preset. Use
0 30 9 * * 1-5or@at_18:30. TypeScript rejects a preset it doesn’t recognise. - No pile-ups. If a run is still going when the next one is due, the new one is skipped and counted.
- Failures stay contained. A callback that throws is caught and reported, and the job keeps its schedule.
- You can see what happened. Every job keeps totals, average duration, its last error and recent runs.
import Baker from "cronbake";
const baker = Baker.create({
onError: (error, job) => report(job, error),
});
baker.add({
name: "send-digests",
cron: "0 30 9 * * 1-5", // 09:30, Monday to Friday
callback: async () => {
await sendDigests();
},
});
baker.add({
name: "refresh-rates",
cron: "@every_5_minutes",
immediate: true, // also run once at startup
callback: refreshRates,
});
baker.bakeAll();
// Later, from a health check or an admin page
baker.getStatus("send-digests"); // "running"
baker.nextExecution("send-digests"); // Date
baker.getMetrics("send-digests").failedExecutions; // 0Where it fits
A long-running server or worker that has to do things on a schedule: clearing expired sessions, sending digests, refreshing a cache.
The package has no dependencies and comes to about 7 KB gzipped. There is nothing else to run.
Where it doesn’t
Serverless functions, since no process stays alive between requests. Several copies of the same app, unless you choose one to run the scheduler, because there is no distributed lock.
Work that has to happen no matter what. Missed ticks aren’t replayed and failed runs aren’t retried, so use a queue for that. More on running in production.