Cron Jobs and Scheduling in bunqueue
Background jobs aren’t always triggered by user actions. Many tasks need to run on a schedule: daily reports, hourly cleanups, periodic syncs. bunqueue has a built-in cron scheduler that runs alongside your job queue with zero additional infrastructure.
Two Types of Scheduled Jobs
bunqueue supports two scheduling modes:
| Mode | Use Case | Example |
|---|---|---|
| Cron expression | Calendar-based schedules | ”Every Monday at 9am” |
| Repeat interval | Fixed interval | ”Every 5 minutes” |
Cron Expressions
Use standard cron syntax for calendar-based schedules:
import { Queue } from 'bunqueue/client';
const queue = new Queue('reports', { embedded: true });
// Daily at midnight UTCawait queue.upsertJobScheduler('daily-report', { pattern: '0 0 * * *',}, { name: 'generate-report', data: { type: 'daily' },});
// Every Monday at 9:00 AMawait queue.upsertJobScheduler('weekly-digest', { pattern: '0 9 * * 1',}, { name: 'send-digest', data: { type: 'weekly' },});
// Every 15 minutesawait queue.upsertJobScheduler('health-check', { pattern: '*/15 * * * *',}, { name: 'check-health', data: { service: 'api' },});Repeat Intervals
For simple fixed-interval schedules, use every:
// Every 5 minutes (300,000 ms)await queue.upsertJobScheduler('sync-data', { every: 300_000,}, { name: 'sync', data: { source: 'external-api' },});Timezone Support
Cron expressions default to UTC. Specify a timezone for local-time scheduling:
// 9:00 AM New York time (handles DST automatically)await queue.upsertJobScheduler('morning-report', { pattern: '0 9 * * *', tz: 'America/New_York',}, { name: 'morning-report', data: {},});
// 6:00 PM Tokyo timeawait queue.upsertJobScheduler('evening-cleanup', { pattern: '0 18 * * *', tz: 'Asia/Tokyo',}, { name: 'cleanup', data: {},});Execution Limits
Prevent runaway cron jobs with execution limits:
// Run at most 100 times, then stopawait queue.upsertJobScheduler('limited-task', { pattern: '*/5 * * * *', limit: 100,}, { name: 'task', data: {},});Managing Scheduled Jobs
List, inspect, and remove schedulers:
// List all schedulersconst schedulers = await queue.getJobSchedulers();for (const s of schedulers) { console.log(s.name, s.pattern || s.every, s.next);}
// Get a specific schedulerconst scheduler = await queue.getJobScheduler('daily-report');console.log(scheduler);
// Remove a schedulerawait queue.removeJobScheduler('daily-report');
// Count schedulersconst count = await queue.getJobSchedulersCount();Event-Driven Scheduler Architecture
bunqueue’s scheduler uses an event-driven design with precise setTimeout instead of polling:
Scheduler Tick │ ├── Calculate next cron/repeat fire time ├── setTimeout(fireTime - now) │ └── On fire: ├── Create job in the queue ├── Update execution count ├── Calculate next fire time └── Schedule next setTimeoutThis means zero CPU usage between scheduled events. The scheduler only wakes up when a job needs to fire.
Cron + Workers: Complete Example
Here’s a complete pattern for a scheduled data sync:
import { Queue, Worker } from 'bunqueue/client';
const queue = new Queue('sync', { embedded: true });
// Schedule: every hourawait queue.upsertJobScheduler('hourly-sync', { pattern: '0 * * * *',}, { name: 'sync-users', data: { source: 'external-api' }, opts: { attempts: 3, backoff: { type: 'exponential', delay: 5000 }, timeout: 120_000, // 2 minute timeout },});
// Worker processes the scheduled jobsconst worker = new Worker('sync', async (job) => { const { source } = job.data; await job.log(`Starting sync from ${source}`);
const users = await fetchUsersFromAPI(source); await job.updateProgress(50);
await saveUsersToDatabase(users); await job.updateProgress(100);
return { synced: users.length };}, { embedded: true });
worker.on('completed', (job, result) => { console.log(`Synced ${result.synced} users`);});CLI Management
Manage cron jobs from the command line:
# List all cron jobsbunqueue cron list
# Add a cron jobbunqueue cron add --name daily-report --queue reports \ --schedule "0 0 * * *" --data '{"type":"daily"}'
# Delete a cron jobbunqueue cron delete --name daily-report