Jobs
Everything you need to know about defining, enqueueing, and managing jobs.
Defining Jobs
Use defineJob to create a type-safe job:
jobs/send-email.ts
import { pidgey } from '@/lib/pidgey';
export const sendEmail = pidgey.defineJob({
name: 'send-email',
handler: async (data: { to: string; subject: string }) => {
await emailService.send(data);
return { sent: true };
},
config: {
retries: 3,
timeout: 30000,
},
});Config options:
| Option | Default | Description |
|---|---|---|
retries | 3 | Max retry attempts |
timeout | 300000 | Timeout in ms (5 min) |
queue | job name | Queue name |
Enqueueing Jobs
Basic enqueue
await sendEmail.enqueue({
to: 'leslie.knope@pawnee.gov',
subject: 'Welcome!',
});Delayed jobs
Schedule a job to run later:
// Run in 1 hour
await sendEmail.enqueue(data, { delay: 3600000 });
// Or use a helper
const ONE_HOUR = 60 * 60 * 1000;
await sendEmail.enqueue(data, { delay: ONE_HOUR });Override config at enqueue time
await sendEmail.enqueue(data, {
maxAttempts: 5, // Override retries
timeout: 60000, // Override timeout
});Retries & Error Handling
Jobs automatically retry on failure with exponential backoff.
export const unreliableJob = pidgey.defineJob({
name: 'call-api',
handler: async (data) => {
const response = await fetch(data.url);
if (!response.ok) {
throw new Error('API failed'); // Will trigger retry
}
return response.json();
},
config: {
retries: 5, // Retry up to 5 times
},
});Backoff schedule: 1s → 2s → 4s → 8s → 16s (exponential)
Manual retry
// Retry a specific failed job
await pidgey.retryJob('job_abc123');
// Retry all failed jobs
await pidgey.retryAllFailed();
// Retry failed jobs in a queue
await pidgey.retryAllFailed('emails');Dead Letter Queue
Jobs that exhaust all retries are moved to the DLQ for debugging.
// List failed jobs
const failed = await pidgey.listJobs({ status: 'failed' });
// View error details
for (const job of failed) {
console.log(job.id, job.error, job.attempts);
}CLI access
# List failed jobs
npx pidgey jobs list --status failed
# Retry all failed
npx pidgey jobs retry --failed
# Delete failed jobs
npx pidgey jobs delete --status failedMultiple Queues
Separate jobs into queues for different processing:
export const urgentEmail = pidgey.defineJob({
name: 'urgent-email',
handler: async (data) => {
/* ... */
},
config: {
queue: 'urgent', // High priority queue
},
});
export const bulkEmail = pidgey.defineJob({
name: 'bulk-email',
handler: async (data) => {
/* ... */
},
config: {
queue: 'bulk', // Background queue
},
});Run workers for specific queues:
# Process only urgent queue with high concurrency
npx pidgey worker start --queue urgent --concurrency 20
# Process bulk queue with low concurrency
npx pidgey worker start --queue bulk --concurrency 2Job Status
Track job lifecycle:
const job = await sendEmail.enqueue(data);
// Check status later
const status = await pidgey.getJob(job.id);
switch (status?.status) {
case 'pending': // Waiting to run
case 'active': // Currently running
case 'completed': // Finished successfully
case 'failed': // Exhausted retries
case 'cancelled': // Manually cancelled
}Cancelling Jobs
Cancel a pending job before it runs:
await pidgey.cancelJob('job_abc123');⚠️
The Redis adapter does not support cancelling jobs. Use deleteJob instead.
Next Steps
- Scheduled Jobs — Cron-based recurring jobs
- Worker — Configure job processing
- API Reference — Full programmatic API