Advanced Features
On this page
Learn how to leverage Dispatched's advanced features to build robust background job processing for your applications.
Job Scheduling
Schedule jobs to run at any time within the next year using ISO 8601 UTC timestamps.
Scheduling Options
{
"payload": {
"task": "generate_report",
"reportId": "annual-2024"
},
"scheduleFor": "2024-12-31T23:59:59Z" // Run on New Year's Eve
}
Schedule Formatting Tips
- Always use UTC timezone
- Include full timestamp (YYYY-MM-DDTHH:mm:ssZ)
- Maximum schedule: 1 year from current time
- Minimum schedule: 1 minute from current time
- Not providing
scheduleFor
will queue the job immediately
Example Use Cases
// Daily report at midnight UTC
{
"payload": { "task": "daily_report" },
"scheduleFor": "2024-12-18T00:00:00Z"
}
// Email reminder in 2 hours
{
"payload": { "task": "send_reminder" },
"scheduleFor": "2024-12-17T14:00:00Z"
}
Retry Management
Dispatched implements a smart retry system for failed jobs with exponential backoff.
Retry Policy
- Maximum attempts: 3
- Backoff intervals: 30s → 2m → 5m
- Retry triggers:
- Non-200/201 HTTP responses
- Timeout exceeded
- Network failures
Tracking Retries
Each webhook request includes retry information:
{
"jobId": "job_abc123",
"attemptId": "attempt_xyz456",
"attemptNumber": 2,
"payload": {
"task": "process_video"
}
}
Handling Retries
app.post('/webhook', async (req, res) => {
const { jobId, attempt, payload } = req.body;
try {
// Log attempt number
console.log(`Processing ${jobId} - Attempt ${attempt}/3`);
// Implement custom retry logic if needed
if (attempt > 1) {
// Maybe use a different processing strategy
await alternativeProcessing(payload);
} else {
await normalProcessing(payload);
}
res.status(200).json({ success: true });
} catch (error) {
// Will trigger retry if attempts remaining
res.status(500).json({ error: error.message });
}
});
Job Monitoring
Monitor your jobs through our dashboard and API.
Job Statuses
{
QUEUED: "Job is waiting to be processed",
STARTED: "Job processing has begun",
DISPATCHED: "Job sent to webhook URL",
COMPLETED: "Job successfully processed",
CANCELLED: "Job manually cancelled",
FAILED: "Job failed after all retries"
}
Dashboard Features
Access comprehensive job information at dispatched.dev/app/jobs:
- Real-time job status
- Full execution history
- Retry attempts and outcomes
- Payload inspection
- Error logs and debugging info
Filtering and Search
Filter jobs by:
- Status
- Date range
- Job ID
- Custom payload properties
Timeout Management
Each subscription tier has specific timeout limits for job processing.
Timeout Limits
Plan | Max Timeout |
---|---|
Starter | 30 seconds |
Pro | 5 minutes |
Enterprise | Custom |
Handling Long-Running Jobs
For jobs that might exceed timeout limits:
- Break into smaller sub-jobs:
// Instead of one large job
{
"payload": {
"task": "process_large_video",
"videoId": "123"
}
}
// Break into chunks
{
"payload": {
"task": "process_video_chunk",
"videoId": "123",
"chunkIndex": 1,
"totalChunks": 10
}
}
- Use job chaining:
app.post('/webhook', async (req, res) => {
const { payload } = req.body;
// Process current chunk
await processVideoChunk(payload);
// Queue next chunk if needed
if (payload.chunkIndex < payload.totalChunks) {
await queueNextChunk({
...payload,
chunkIndex: payload.chunkIndex + 1
});
}
res.status(200).json({ success: true });
});
Production Best Practices
Idempotency
Design your webhook handlers to be idempotent:
app.post('/webhook', async (req, res) => {
const { jobId, txn } = req.body;
// Check if we've already processed this transaction
if (await hasProcessedTransaction(txn)) {
return res.status(200).json({ status: 'already_processed' });
}
// Process job
await processJob(req.body);
// Record transaction as processed
await markTransactionProcessed(txn);
res.status(200).json({ status: 'success' });
});
Error Handling
Implement comprehensive error handling:
app.post('/webhook', async (req, res) => {
try {
// Validate webhook signature
validateWebhookSignature(req);
// Process the job
await processJob(req.body);
res.status(200).json({ status: 'success' });
} catch (error) {
// Log error details
console.error(`Job ${req.body.jobId} failed:`, error);
if (error.retryable) {
// Return 500 to trigger retry
res.status(500).json({ error: error.message });
} else {
// Mark as completed but failed
res.status(200).json({
status: 'failed',
error: error.message
});
}
}
});
Next Steps
- Review our API Reference for detailed endpoint documentation
- Check out our Troubleshooting Guide for common issues
- Explore Pricing & Limits for your use case
Need help? Contact our support team at support@dispatched.dev