Jobs

Pidgey 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:

OptionDefaultDescription
retries3Max retry attempts
timeout300000Timeout in ms (5 min)
queuejob nameQueue 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 failed

Multiple 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 2

Job 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