Overview
The cron() function schedules recurring tasks using cron expressions. Perfect for automated messages, cleanups, reminders, and periodic maintenance.
Signature
function cron (
name : string ,
cronExpr : string ,
handler : ( ctx : CronContext ) => void | Promise < void >,
options ?: CronOptions
) : void
Parameters
Unique identifier for this cron job
Cron expression defining when the job runs (see Cron Syntax )
Function to execute on schedule Receives CronContext with:
name - The cron job name
scheduledAt - ISO8601 timestamp of when execution was scheduled
Optional configuration Show CronOptions properties
Skip execution if the previous run is still in progress
Return Value
Returns void. The cron job is registered immediately.
Cron Syntax
Cron expressions use 5 fields:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *
Special Characters
* - Any value
, - Value list separator (e.g., 1,15 = 1st and 15th)
- - Range (e.g., 1-5 = 1 through 5)
/ - Step values (e.g., */15 = every 15 units)
Common Patterns
Expression Description * * * * *Every minute 0 * * * *Every hour (at minute 0) 0 0 * * *Every day at midnight 0 0 * * 0Every Sunday at midnight 0 9 * * 1-5Every weekday at 9 AM */15 * * * *Every 15 minutes 0 */6 * * *Every 6 hours 0 0 1 * *First day of every month 0 0 1 1 *Every January 1st
Examples
Daily Reminder
cron ( 'daily-reminder' , '0 9 * * *' , async ( ctx ) => {
const channel = '123456789' // Your channel ID
await rest . sendMessage ({
channelId: channel ,
content: 'Good morning! Don \' t forget to check the announcements.'
})
})
Hourly Cleanup
cron ( 'cleanup' , '0 * * * *' , async ( ctx ) => {
const db = kv . store ( 'cache' )
// List all temporary keys
const result = await db . list ({ prefix: 'temp:' })
// Delete expired entries
for ( const key of result . keys ) {
await db . delete ( key . name )
}
console . log ( `Cleaned up ${ result . keys . length } temporary entries at ${ ctx . scheduledAt } ` )
})
Weekly Stats Report
cron ( 'weekly-report' , '0 18 * * 5' , async ( ctx ) => {
const statsChannel = '987654321'
const points = kv . store ( 'points' )
const allUsers = await points . list ({ prefix: 'user:' })
const topUsers = allUsers . keys
. sort (( a , b ) => parseInt ( b . name ) - parseInt ( a . name ))
. slice ( 0 , 10 )
const reportEmbed = embed ()
. setTitle ( '📊 Weekly Leaderboard' )
. setDescription ( 'Top 10 users this week' )
. setColor ( 0x00FF00 )
. setTimestamp ( ctx . scheduledAt )
. toJSON ()
await rest . sendMessage ({
channelId: statsChannel ,
embeds: [ reportEmbed ]
})
}, { skipIfRunning: true })
Every 15 Minutes Check
cron ( 'status-check' , '*/15 * * * *' , async ( ctx ) => {
// Runs at :00, :15, :30, :45 of every hour
console . log ( 'Running status check at' , ctx . scheduledAt )
// Your monitoring logic here
})
Multiple Jobs
// Backup every 6 hours
cron ( 'backup' , '0 */6 * * *' , async ( ctx ) => {
console . log ( 'Creating backup...' )
// Backup logic
})
// Clear cache every hour
cron ( 'clear-cache' , '0 * * * *' , async ( ctx ) => {
console . log ( 'Clearing cache...' )
// Cache clearing logic
})
// Send daily digest at 6 PM
cron ( 'daily-digest' , '0 18 * * *' , async ( ctx ) => {
console . log ( 'Sending daily digest...' )
// Digest logic
})
Using skipIfRunning
// Long-running task that shouldn't overlap
cron ( 'data-sync' , '*/5 * * * *' , async ( ctx ) => {
console . log ( 'Starting data sync...' )
// Simulate long operation
await new Promise ( resolve => setTimeout ( resolve , 7 * 60 * 1000 )) // 7 minutes
console . log ( 'Data sync complete' )
}, { skipIfRunning: true })
// If sync takes >5 minutes, the next scheduled run will be skipped
Context Properties
The name of the cron job (same as first parameter)
ISO8601 timestamp of when this execution was scheduled
Best Practices
Use Unique Names
// Good - unique, descriptive names
cron ( 'daily-welcome' , '0 9 * * *' , handler )
cron ( 'hourly-cleanup' , '0 * * * *' , handler )
// Avoid - generic names that might conflict
cron ( 'task' , '0 * * * *' , handler )
Handle Errors
cron ( 'risky-task' , '0 0 * * *' , async ( ctx ) => {
try {
await performRiskyOperation ()
} catch ( error ) {
console . error ( 'Cron job failed:' , error )
// Optional: send alert to admin channel
}
})
Use skipIfRunning for Long Tasks
cron ( 'long-running' , '*/10 * * * *' , async ( ctx ) => {
// Task that might take >10 minutes
await heavyOperation ()
}, { skipIfRunning: true })
Log Execution
cron ( 'important-task' , '0 */6 * * *' , async ( ctx ) => {
console . log ( `[ ${ ctx . name } ] Starting at ${ ctx . scheduledAt } ` )
await performTask ()
console . log ( `[ ${ ctx . name } ] Completed successfully` )
})
Notes
Cron jobs are registered per guild
Times are in UTC (not local timezone)
Minimum interval is 1 minute
Handler can be async or sync
Multiple handlers with the same name will all execute
Use skipIfRunning: true for tasks that might take longer than their interval
Cron expressions are validated when cron() is called
Timezone Considerations
All cron times are in UTC . To schedule for a specific timezone:
// 9 AM EST = 2 PM UTC (EST is UTC-5, or UTC-4 during DST)
cron ( 'est-morning' , '0 14 * * *' , handler )
// 6 PM PST = 2 AM UTC next day (PST is UTC-8, or UTC-7 during PDT)
cron ( 'pst-evening' , '0 2 * * *' , handler )
Consider using a library to calculate UTC offsets if needed.