Scheduler#
Cron-based task scheduling using croner. Run tasks on a schedule - daily cleanups, periodic reports, health checks.
Basic Usage#
typescript
import { Scheduler } from "@buntok/core/schedule";
const scheduler = new Scheduler();
// Run every minute
scheduler.schedule("* * * * *", () => {
console.log("Running every minute");
});
// Run daily at midnight
scheduler.schedule("0 0 * * *", async () => {
await cleanupOldRecords();
});
// Run every 5 minutes
scheduler.schedule("*/5 * * * *", async () => {
await syncExternalData();
});Scheduler API#
| Method | Description |
|---|---|
| scheduler.schedule(pattern, handler) | Register a cron job |
| scheduler.stopAll() | Stop all scheduled jobs |
Cron Patterns#
| Pattern | Description |
|---|---|
| * * * * * | Every minute |
| 0 * * * * | Every hour (at minute 0) |
| 0 0 * * * | Daily at midnight |
| 0 0 * * 1 | Weekly on Monday at midnight |
| 0 0 1 * * | Monthly on the 1st at midnight |
| */5 * * * * | Every 5 minutes |
| 0 9-17 * * 1-5 | Every hour from 9am-5pm, Mon-Fri |
| 30 4 1,15 * * | 4:30am on 1st and 15th of month |
@CronJob Decorator#
Schedule a controller method as a cron job. The job is bound to the class instance, so this works correctly:
typescript
import { Controller, Get } from "@buntok/core";
import { CronJob } from "@buntok/core/schedule";
class CacheService {
deletePattern(pattern: string) { /* ... */ }
}
@Controller("/tasks")
class TaskController {
constructor(private readonly cache: CacheService) {}
@CronJob("0 0 * * *") // Daily at midnight
async dailyCleanup() {
// 'this' is the TaskController instance
await this.cache.deletePattern("tmp:*");
console.log("Cache cleaned");
}
@CronJob("*/5 * * * *") // Every 5 minutes
async syncData() {
await this.fetchExternalAPI();
}
}Info
The
@CronJob decorator uses context.addInitializer so the job is scheduled when the class is instantiated, not at definition time. This means this and injected services work correctly.Drivers#
| Driver | Description |
|---|---|
| MemorySchedulerDriver | In-memory cron via croner (default) |
| BunCronSchedulerDriver | OS-level cron via Bun.cron() - survives restarts |
BunCronSchedulerDriver#
Uses Bun's native Bun.cron() API to register jobs with the OS scheduler (crontab on Linux, launchd on macOS, Task Scheduler on Windows). Jobs survive process restarts. Requires Bun >= 1.3.11.
typescript
import { Scheduler, BunCronSchedulerDriver } from "@buntok/core/schedule";
const scheduler = new Scheduler(new BunCronSchedulerDriver());
scheduler.schedule("0 0 * * *", async () => {
await dailyCleanup();
});Setting Default Driver for @CronJob#
Use setDefaultSchedulerDriver to make the @CronJob decorator use BunCronSchedulerDriver instead of the in-memory driver:
typescript
import { setDefaultSchedulerDriver, BunCronSchedulerDriver } from "@buntok/core/schedule";
// Call before any @CronJob classes are instantiated
setDefaultSchedulerDriver(new BunCronSchedulerDriver());Full Example#
typescript
import { Buntok } from "@buntok/core";
import { Scheduler } from "@buntok/core/schedule";
const app = new Buntok();
const scheduler = new Scheduler();
// Clean up old sessions every hour
scheduler.schedule("0 * * * *", async () => {
await db.session.deleteMany({
where: { expiresAt: { lt: new Date() } },
});
console.log("Expired sessions cleaned");
});
// Generate daily report
scheduler.schedule("0 2 * * *", async () => {
const report = await generateDailyReport();
await mailer.send({
to: "admin@example.com",
subject: "Daily Report",
html: report,
});
});
// Health check every minute
scheduler.schedule("* * * * *", async () => {
const healthy = await checkDatabase();
if (!healthy) {
await alertOps("Database is down!");
}
});
app.listen(1212);