Introduction
@warlock.js/scheduler runs your recurring background work — the nightly cleanup, the hourly sync, that 9 AM report — on a schedule you write in plain English or a cron string. Timezones, retries, overlap guards, and graceful shutdown are built in, so the boring-but-critical parts are handled for you.
Installation
Section titled “Installation”npm install @warlock.js/schedulerQuick Start
Section titled “Quick Start”import { scheduler, job } from "@warlock.js/scheduler";
// Clean up expired tokens every night at 3 AMscheduler.addJob( job("cleanup", async () => { await db.deleteExpiredTokens(); }) .daily() .at("03:00"));
scheduler.start();That’s it. scheduler is a ready-to-use singleton — no configuration required for simple use cases.
Two Scheduling Styles
Section titled “Two Scheduling Styles”Fluent API
Section titled “Fluent API”The fluent API is the recommended approach. It reads like plain English:
import { job } from "@warlock.js/scheduler";
// Every day at 9 AMjob("morning-report", sendReport).daily().at("09:00");
// Every Monday at midnightjob("weekly-cleanup", cleanupOldData).weekly().on("monday");
// Every 15 minutesjob("heartbeat", pingHealthCheck).everyMinutes(15);
// First of each month at midnightjob("monthly-invoice", generateInvoices).monthly().on(1).at("00:00");Cron Expressions
Section titled “Cron Expressions”Use raw cron syntax when you need precise schedules or are migrating from an existing cron-based system:
import { job } from "@warlock.js/scheduler";
// 9 AM on weekdays (Monday–Friday)job("standup-reminder", sendReminder).cron("0 9 * * 1-5");
// Every 5 minutesjob("cache-refresh", refreshCache).cron("*/5 * * * *");
// First day of every month at midnightjob("monthly-report", generateMonthlyReport).cron("0 0 1 * *");Cron field reference:
┌───────────── minute (0-59)│ ┌───────────── hour (0-23)│ │ ┌───────────── day of month (1-31)│ │ │ ┌───────────── month (1-12)│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)│ │ │ │ │* * * * *Supported field syntax: *, 5, 1,3,5, 1-5, */5, 1-10/2.
The Scheduler Singleton
Section titled “The Scheduler Singleton”For most apps, import the built-in scheduler singleton directly:
import { scheduler, job } from "@warlock.js/scheduler";
scheduler .addJob(job("job-a", taskA).daily().at("02:00")) .addJob(job("job-b", taskB).everyHour()) .start();When you need multiple isolated schedulers (e.g. in tests or separate process pools), instantiate Scheduler directly:
import { Scheduler, job } from "@warlock.js/scheduler";
const myScheduler = new Scheduler();myScheduler.addJob(job("isolated-task", runTask).everyMinutes(5));myScheduler.start();Graceful Shutdown
Section titled “Graceful Shutdown”Always wire up shutdown so running jobs can finish cleanly before the process exits:
import { scheduler } from "@warlock.js/scheduler";
scheduler.start();
process.on("SIGTERM", async () => { // Waits up to 30 s for running jobs to finish (default timeout) await scheduler.shutdown(); process.exit(0);});What’s Next
Section titled “What’s Next”| Topic | Description |
|---|---|
| Defining Jobs | Full fluent API reference — every timing method |
| Retry & Backoff | Automatic retries with optional exponential backoff |
| Overlap Prevention | Skip a run if the previous one is still going |
| Timezone | Per-job timezone support with IANA strings |
| Events | Observe the full job lifecycle |
| Configuration | Tick interval, parallel execution, concurrency |