Skip to content

Commit a948214

Browse files
committed
chore: wip
1 parent 090bbb9 commit a948214

6 files changed

Lines changed: 631 additions & 1 deletion

File tree

docs/cron-expressions.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Cron Expressions Guide
2+
3+
`bun-queue` supports native cron syntax for scheduling recurring jobs with timezone support. This guide helps you understand how to write cron expressions and provides common examples you can use in your applications.
4+
5+
## Cron Expression Format
6+
7+
A cron expression consists of five fields that specify when a job should run:
8+
9+
```
10+
┌───────────── minute (0 - 59)
11+
│ ┌───────────── hour (0 - 23)
12+
│ │ ┌───────────── day of month (1 - 31)
13+
│ │ │ ┌───────────── month (1 - 12)
14+
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
15+
│ │ │ │ │
16+
│ │ │ │ │
17+
* * * * *
18+
```
19+
20+
### Special Characters
21+
22+
- `*`: Matches any value (wildcard)
23+
- `,`: Separates multiple values (e.g., `1,3,5`)
24+
- `-`: Specifies a range (e.g., `1-5`)
25+
- `/`: Specifies a step value (e.g., `*/2` means every 2 units)
26+
27+
## Common Cron Expressions
28+
29+
Here are some commonly used cron expressions:
30+
31+
| Expression | Description |
32+
|------------|-------------|
33+
| `* * * * *` | Every minute |
34+
| `0 * * * *` | Every hour (at minute 0) |
35+
| `0 0 * * *` | Every day at midnight |
36+
| `0 0 * * 0` | Every Sunday at midnight |
37+
| `0 0 1 * *` | First day of every month at midnight |
38+
| `0 0 1 1 *` | January 1st at midnight (once a year) |
39+
| `0 12 * * 1-5` | Every weekday at noon |
40+
| `0 */2 * * *` | Every 2 hours |
41+
| `*/15 * * * *` | Every 15 minutes |
42+
| `0 8-17 * * 1-5` | Every hour from 8am to 5pm on weekdays |
43+
| `0 9 * * 1` | Every Monday at 9am |
44+
45+
## Timezone Support
46+
47+
Bun Bull supports timezone specifications for cron jobs. This allows you to schedule jobs according to a specific timezone rather than server time.
48+
49+
Example with timezone:
50+
51+
```typescript
52+
await queue.scheduleCron({
53+
cronExpression: '30 9 * * *', // Every day at 9:30am
54+
timezone: 'America/New_York', // Eastern Time
55+
data: {
56+
// job data
57+
}
58+
})
59+
```
60+
61+
### Common Timezones
62+
63+
- `UTC`: Coordinated Universal Time
64+
- `America/New_York`: Eastern Time (US & Canada)
65+
- `America/Chicago`: Central Time (US & Canada)
66+
- `America/Denver`: Mountain Time (US & Canada)
67+
- `America/Los_Angeles`: Pacific Time (US & Canada)
68+
- `Europe/London`: UK time
69+
- `Europe/Paris`: Central European Time
70+
- `Asia/Tokyo`: Japan Standard Time
71+
- `Australia/Sydney`: Australian Eastern Time
72+
73+
## Advanced Examples
74+
75+
### First Monday of the Month
76+
77+
To schedule a job to run on the first Monday of each month:
78+
79+
```
80+
0 12 1-7 * 1
81+
```
82+
83+
This runs at 12:00pm on Mondays (day of week = 1) that occur between the 1st and 7th day of the month.
84+
85+
### Last Day of the Month
86+
87+
This is trickier and is not directly supported by cron syntax. Instead, you might need to:
88+
89+
1. Schedule a daily job
90+
2. Check in your job handler if it's the last day of the month
91+
92+
### Specific Complex Schedules
93+
94+
For more complex scheduling needs, you might need to combine multiple cron expressions or use custom logic in your job handler.
95+
96+
## Using Cron Jobs in Bun Bull
97+
98+
```typescript
99+
import { Queue, type CronJobOptions } from 'bun-queue'
100+
101+
// Create a queue
102+
const queue = new Queue('my-queue')
103+
104+
// Schedule a cron job
105+
await queue.scheduleCron({
106+
cronExpression: '0 0 * * *', // Daily at midnight
107+
timezone: 'UTC',
108+
data: {
109+
// Your job data
110+
},
111+
// Other job options
112+
limit: 30, // Run at most 30 times
113+
jobId: 'daily-job' // Custom job ID
114+
})
115+
116+
// Unschedule a cron job
117+
await queue.unscheduleCron('daily-job')
118+
```
119+
120+
## Best Practices
121+
122+
1. **Be specific**: Avoid using `* * * * *` (every minute) in production as it can overload your system.
123+
2. **Use jobId**: Always provide a jobId for cron jobs so you can easily unschedule them later.
124+
3. **Test timezone logic**: If using timezones, test to ensure jobs run at the expected time.
125+
4. **Set limits**: Consider using the `limit` option to ensure jobs don't run indefinitely.
126+
5. **Handle edge cases**: Be aware of edge cases like months with varying numbers of days.
127+
128+
## Additional Resources
129+
130+
- [Crontab Guru](https://crontab.guru/): Interactive cron expression editor
131+
- [List of TZ database time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones): Complete list of valid timezone identifiers

examples/cron-jobs.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { Queue } from '../src'
2+
3+
interface NotificationData {
4+
title: string
5+
message: string
6+
recipients: string[]
7+
type: 'email' | 'push' | 'sms'
8+
}
9+
10+
async function main() {
11+
console.log('🕒 Cron Jobs Example')
12+
13+
// Create a queue for notifications
14+
const notificationQueue = new Queue<NotificationData>('notifications', {
15+
verbose: true,
16+
logLevel: 'info',
17+
})
18+
19+
console.log('✅ Queue created')
20+
21+
// Process notifications
22+
notificationQueue.process(5, async (job) => {
23+
const { title, message, recipients, type } = job.data
24+
console.log(`📨 Processing ${type} notification "${title}" to ${recipients.length} recipients`)
25+
26+
// Simulate notification sending
27+
await new Promise(resolve => setTimeout(resolve, 200))
28+
29+
return { success: true, sentAt: new Date(), recipientCount: recipients.length }
30+
})
31+
32+
console.log('\n📅 Scheduling cron jobs with different expressions:')
33+
34+
// Example 1: Run every minute - useful for testing
35+
const everyMinuteId = await notificationQueue.scheduleCron({
36+
cronExpression: '* * * * *', // Every minute
37+
data: {
38+
title: 'Server Status',
39+
message: 'All systems operational',
40+
recipients: ['admin@example.com'],
41+
type: 'email'
42+
},
43+
jobId: 'status-check-minute',
44+
// Will stop after 5 executions
45+
limit: 5
46+
})
47+
console.log(` - Every minute status check scheduled (ID: ${everyMinuteId})`)
48+
49+
// Example 2: Hourly job with timezone
50+
const hourlyJobId = await notificationQueue.scheduleCron({
51+
cronExpression: '0 * * * *', // At minute 0 of every hour
52+
timezone: 'America/New_York', // Eastern Time
53+
data: {
54+
title: 'Hourly Update',
55+
message: 'This is your hourly system update',
56+
recipients: ['team@example.com'],
57+
type: 'push'
58+
},
59+
jobId: 'hourly-update'
60+
})
61+
console.log(` - Hourly update scheduled in Eastern Time (ID: ${hourlyJobId})`)
62+
63+
// Example 3: Daily job at specific time
64+
const dailyJobId = await notificationQueue.scheduleCron({
65+
cronExpression: '30 9 * * *', // Every day at 9:30am
66+
timezone: 'Europe/London', // London time
67+
data: {
68+
title: 'Daily Report',
69+
message: 'Here is your daily activity report',
70+
recipients: ['manager@example.com'],
71+
type: 'email'
72+
},
73+
jobId: 'daily-report'
74+
})
75+
console.log(` - Daily report scheduled for 9:30am London time (ID: ${dailyJobId})`)
76+
77+
// Example 4: Weekday job (Monday through Friday)
78+
const weekdayJobId = await notificationQueue.scheduleCron({
79+
cronExpression: '0 8 * * 1-5', // At 8:00am, Monday through Friday
80+
data: {
81+
title: 'Morning Briefing',
82+
message: 'Your tasks for today',
83+
recipients: ['staff@example.com'],
84+
type: 'sms'
85+
},
86+
jobId: 'weekday-briefing'
87+
})
88+
console.log(` - Weekday briefing scheduled for 8:00am Mon-Fri (ID: ${weekdayJobId})`)
89+
90+
// Example 5: Complex schedule (first Monday of the month)
91+
const monthlyJobId = await notificationQueue.scheduleCron({
92+
cronExpression: '0 12 1-7 * 1', // At 12:00pm on Monday in the first week of the month
93+
data: {
94+
title: 'Monthly Review',
95+
message: 'Time for our monthly performance review',
96+
recipients: ['executives@example.com'],
97+
type: 'email'
98+
},
99+
jobId: 'monthly-review'
100+
})
101+
console.log(` - Monthly review scheduled for first Monday of each month (ID: ${monthlyJobId})`)
102+
103+
// Show when the next few minutes of jobs will run
104+
console.log('\n⏰ Demonstrating minute-by-minute execution for a short period:')
105+
console.log(' (The every-minute job will run several times)')
106+
107+
// Wait for several minutes to see some executions
108+
await new Promise(resolve => setTimeout(resolve, 180000)) // 3 minutes
109+
110+
// Unschedule one of the jobs to demonstrate cancellation
111+
console.log('\n❌ Unscheduling the every-minute job')
112+
const unscheduled = await notificationQueue.unscheduleCron(everyMinuteId)
113+
console.log(` Job ${everyMinuteId} ${unscheduled ? 'successfully unscheduled' : 'failed to unschedule'}`)
114+
115+
// Show the remaining scheduled jobs
116+
console.log('\n📝 The following jobs remain scheduled:')
117+
console.log(` - Hourly update (ID: ${hourlyJobId})`)
118+
console.log(` - Daily report (ID: ${dailyJobId})`)
119+
console.log(` - Weekday briefing (ID: ${weekdayJobId})`)
120+
console.log(` - Monthly review (ID: ${monthlyJobId})`)
121+
122+
console.log('\n👋 Example completed. In a real application, these would continue running.')
123+
console.log(' Closing the queue for the example.')
124+
125+
// In a real application, you might keep the queue running forever
126+
await notificationQueue.close()
127+
}
128+
129+
main().catch(error => {
130+
console.error('Error in example:', error)
131+
process.exit(1)
132+
})

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
"example:advanced-features": "bun examples/advanced-features.ts",
6868
"example:priority-queue": "bun examples/priority-queue.ts",
6969
"example:key-rate-limiting": "bun examples/key-rate-limiting.ts",
70-
"example:distributed-locks": "bun examples/distributed-locks.ts"
70+
"example:distributed-locks": "bun examples/distributed-locks.ts",
71+
"example:cron-jobs": "bun examples/cron-jobs.ts"
7172
},
7273
"devDependencies": {
7374
"@stacksjs/docs": "^0.70.23",

0 commit comments

Comments
 (0)