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#

MethodDescription
scheduler.schedule(pattern, handler)Register a cron job
scheduler.stopAll()Stop all scheduled jobs

Cron Patterns#

PatternDescription
* * * * *Every minute
0 * * * *Every hour (at minute 0)
0 0 * * *Daily at midnight
0 0 * * 1Weekly on Monday at midnight
0 0 1 * *Monthly on the 1st at midnight
*/5 * * * *Every 5 minutes
0 9-17 * * 1-5Every 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#

DriverDescription
MemorySchedulerDriverIn-memory cron via croner (default)
BunCronSchedulerDriverOS-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);