Cron Triggers
Schedule your workers to run on a recurring basis using cron expressions.
Cron Triggers
Ploy Cron Triggers let you schedule your workers to run automatically on a recurring basis. Define cron expressions in your ploy.yaml and implement a scheduled handler to process them.
Configuration
Add cron triggers in your ploy.yaml:
kind: worker
build: pnpm build
out: dist
cron:
EVERY_MINUTE: "* * * * *"
HOURLY_CLEANUP: "0 * * * *"
DAILY_REPORT: "0 9 * * *"Each key is a trigger name (uppercase with underscores) and the value is a standard cron expression with 5 fields:
# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12)
# │ │ │ │ ┌───────────── day of week (0-6, 0=Sunday)
# │ │ │ │ │
# * * * * *Basic Example
export default {
async fetch(request, env) {
return new Response("Hello from cron worker!");
},
async scheduled(event) {
console.log(`Cron triggered: ${event.cron}`);
console.log(
`Scheduled time: ${new Date(event.scheduledTime).toISOString()}`,
);
// Your scheduled logic here
await performCleanup();
},
} satisfies Ploy;ScheduledEvent
The scheduled handler receives a ScheduledEvent with the following properties:
interface ScheduledEvent {
/** The cron expression that triggered this execution */
cron: string;
/** Timestamp when the event was scheduled (ms since epoch) */
scheduledTime: number;
/** Call to signal this invocation should not be retried */
noRetry: () => void;
}Cron Expression Syntax
Standard 5-field cron expressions are supported:
| Expression | Description |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour |
0 0 * * * | Every day at midnight |
0 9 * * 1-5 | Weekdays at 9 AM |
0 0 1 * * | First day of every month |
30 2 * * 0 | Sundays at 2:30 AM |
Supported Syntax
- Wildcards:
*matches all values - Specific values:
5matches exactly 5 - Ranges:
1-5matches 1 through 5 - Steps:
*/15matches every 15th value - Lists:
1,3,5matches 1, 3, and 5 - Combined:
1-10/2matches 1, 3, 5, 7, 9
Multiple Triggers
You can define multiple cron triggers, each identified by a unique name:
cron:
CLEANUP: "0 * * * *"
DAILY_DIGEST: "0 9 * * *"
WEEKLY_REPORT: "0 10 * * 1"Use the event.cron property to distinguish which trigger fired:
async scheduled(event) {
switch (event.cron) {
case "0 * * * *":
await runCleanup();
break;
case "0 9 * * *":
await sendDailyDigest();
break;
case "0 10 * * 1":
await generateWeeklyReport();
break;
}
}Using with the Start SDK
If you're using @meetploy/start, register a scheduled handler with .scheduled():
import { ploy } from "@meetploy/start";
const app = ploy<PloyEnv>()
.get(
"/",
{
response: z.object({ status: z.string() }),
},
() => ({ status: "ok" }),
)
.scheduled(async (event, env, ctx) => {
console.log(`Cron: ${event.cron}`);
// Your scheduled logic
})
.build();
export default app;Combining with Other Bindings
Cron triggers work alongside other Ploy bindings. Use queues, databases, and caches from your scheduled handler:
kind: worker
build: pnpm build
out: dist
db:
DB: default
queue:
TASKS: tasks
cron:
HOURLY_SYNC: "0 * * * *"async scheduled(event, env) {
// Query your database
const staleRecords = await env.DB.prepare(
"SELECT id FROM records WHERE updated_at < ?"
).bind(Date.now() - 86400000).all();
// Queue work for processing
for (const record of staleRecords.results) {
await env.TASKS.send({ action: "refresh", recordId: record.id });
}
}The scheduled handler has access to the same env bindings as your fetch
handler.
Local Development
When running the emulator with ploy dev, cron triggers are automatically scheduled based on your ploy.yaml configuration. The emulator checks cron expressions every 15 seconds and invokes your scheduled handler when a match occurs.
Cron execution history is visible in the dev dashboard.
Next Steps
How is this guide?
Last updated on