4.6 KiB
4.6 KiB
| title | aliases | tags | sources | created | updated | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Jobs Queue — Quick Start Examples |
|
|
|
2026-05-15 | 2026-05-15 |
Why Use a Job Queue?
Instead of running slow/risky work inline in hooks:
- Non-blocking — API returns immediately; email/heavy work runs async
- Resilience — automatic retries if external service is down
- Scalability — job workers can run on separate servers
- Monitoring — all jobs stored in DB with status + error logs
Example 1: Welcome Email on User Signup
Step 1 — Define the Task (payload.config.ts)
jobs: {
tasks: [
{
slug: 'sendWelcomeEmail',
retries: 3,
inputSchema: [
{ name: 'userEmail', type: 'email', required: true },
{ name: 'userName', type: 'text', required: true },
],
handler: async ({ input, req }) => {
await req.payload.sendEmail({
to: input.userEmail,
subject: 'Welcome!',
text: `Hi ${input.userName}, welcome to our platform!`,
})
return { output: { emailSent: true } }
},
},
],
}
Step 2 — Queue the Job (from a Collection hook)
// In users collection config
hooks: {
afterChange: [
async ({ req, doc, operation }) => {
if (operation === 'create') {
await req.payload.jobs.queue({
task: 'sendWelcomeEmail',
input: { userEmail: doc.email, userName: doc.name },
})
}
},
],
}
Job is stored in payload-jobs collection immediately; runs async — no API delay.
Step 3 — Run Jobs via autoRun
jobs: {
tasks: [ /* ... */ ],
autoRun: [
{ cron: '*/5 * * * *' }, // check every 5 minutes
],
}
Example 2: Scheduled Daily Report (No User Trigger)
Task with schedule Property
{
slug: 'generateDailyReport',
schedule: [
{
cron: '0 8 * * *', // 8:00 AM daily
queue: 'reports',
},
],
handler: async ({ req }) => {
const report = await req.payload.create({ collection: 'reports', data: { /* ... */ } })
return { output: { reportId: report.id } }
},
}
autoRun Must Match the Queue Name
autoRun: [
{
cron: '* * * * *', // check every minute
queue: 'reports', // MUST match schedule.queue
limit: 10,
},
]
Critical gotcha:
schedule.queueandautoRun.queuemust be identical. Mismatch → jobs queued but never executed.
Execution Flow
- 8:00 AM —
scheduleauto-queues a job into'reports'queue - Within 1 min —
autoRuncron finds the job - Execution — report generated
- Next day — repeats automatically
One-Time Future Job (waitUntil)
await payload.jobs.queue({
task: 'publishPost',
input: { postId: '123' },
waitUntil: new Date('2024-12-25T15:00:00Z'),
})
Different from schedule — runs once at specified time, not recurring.
Approach Comparison
| Approach | When to Use | Example |
|---|---|---|
| Manual Queuing | Triggered by user actions / data changes | Welcome emails, payments, notifications |
Scheduled (schedule) |
Automatic recurring at fixed intervals | Daily reports, weekly cleanups, nightly syncs |
waitUntil |
One-time job in the future | Publish at 3pm, trial expiry reminder |
Serverless Warning
autoRun does not work on Vercel/serverless. Use the wiki/payloadcms/jobs-queue-queues with a dedicated API endpoint instead.
Key Takeaways
- Define tasks in
jobs.tasks[]withslug,inputSchema,retries, andhandler - Queue manually:
req.payload.jobs.queue({ task: 'slug', input: {...} }) autoRunpolls for pending jobs on a cron schedule- For scheduled recurring tasks: add
scheduleto the task + matchingqueueinautoRun - Queue names in
schedule.queueandautoRun.queuemust match exactly waitUntil= one-time future job;schedule= recurringautoRundoes not work on serverless (Vercel) — use API endpoint trigger instead
Related Articles
- wiki/payloadcms/jobs-queue
- wiki/payloadcms/jobs-queue-jobs
- wiki/payloadcms/jobs-queue-queues
- wiki/payloadcms/hooks
- wiki/payloadcms/email
Sources
raw/jobs-queue__quick-start-example.md- https://payloadcms.com/docs/jobs-queue/quick-start-example