Base Error
JobQueueError
Base error class for all job queue errors.
Error class name (‘JobQueueError’)
All other error classes extend from JobQueueError.
import { JobQueueError } from '@platformatic/job-queue'
try {
await queue.enqueueAndWait(payload, { timeout: 5000 });
} catch (error) {
if (error instanceof JobQueueError) {
console.error(`Queue error [${error.code}]: ${error.message}`);
}
}
Timeout Errors
TimeoutError
Thrown when enqueueAndWait() exceeds the specified timeout.
Error message including job ID and timeout duration
ID of the job that timed out
Error class name: 'TimeoutError'
When thrown:
- Job doesn’t complete within the specified timeout period in
enqueueAndWait()
- The job continues processing in the background after timeout
import { TimeoutError } from '@platformatic/job-queue'
try {
const result = await queue.enqueueAndWait(
{ task: 'long-running-job' },
{ timeout: 5000 } // 5 seconds
);
console.log('Result:', result);
} catch (error) {
if (error instanceof TimeoutError) {
console.error(`Job ${error.jobId} timed out`);
// Job is still running, you can check status later
const status = await queue.getStatus(error.jobId);
console.log('Current status:', status?.state);
}
}
Retry Errors
MaxRetriesError
Thrown when a job fails permanently after exhausting all retry attempts.
Error message including job ID, attempts, and last error message
Error code: 'MAX_RETRIES'
Number of attempts made before permanent failure
The original error from the final attempt
Error class name: 'MaxRetriesError'
When thrown:
- Job handler throws an error on every retry attempt
- Total attempts reach
maxAttempts (configured in queue or per-job)
- Thrown by
enqueueAndWait() when job fails permanently
import { MaxRetriesError } from '@platformatic/job-queue'
try {
const result = await queue.enqueueAndWait(
{ userId: 123, action: 'send-notification' },
{ maxAttempts: 3 }
);
} catch (error) {
if (error instanceof MaxRetriesError) {
console.error(`Job ${error.jobId} failed after ${error.attempts} attempts`);
console.error('Last error:', error.lastError.message);
// Log to error tracking service
await errorTracker.log({
jobId: error.jobId,
attempts: error.attempts,
error: error.lastError
});
}
}
// Also emitted as 'failed' event
queue.on('failed', (id, error) => {
console.error(`Job ${id} failed permanently:`, error);
});
Job State Errors
JobNotFoundError
Thrown when attempting to operate on a non-existent job.
Error message including job ID
Error code: 'JOB_NOT_FOUND'
ID of the job that was not found
Error class name: 'JobNotFoundError'
When thrown:
- Calling
getStatus() with an invalid or expired job ID
- Job result/error expired due to TTL
- Invalid job ID provided
import { JobNotFoundError } from '@platformatic/job-queue'
try {
const status = await queue.getStatus('invalid-job-id');
} catch (error) {
if (error instanceof JobNotFoundError) {
console.error(`Job ${error.jobId} not found or expired`);
}
}
JobCancelledError
Thrown when waiting for a job that was cancelled.
Error message including job ID
Error code: 'JOB_CANCELLED'
Error class name: 'JobCancelledError'
When thrown:
enqueueAndWait() is waiting for a job that gets cancelled
- Job is cancelled while handler is checking status
import { JobCancelledError } from '@platformatic/job-queue'
// Start a long-running job
const waitPromise = queue.enqueueAndWait(
{ task: 'process-video' },
{ id: 'video-123', timeout: 60000 }
);
// Cancel it from another part of your code
setTimeout(() => {
queue.cancel('video-123');
}, 5000);
try {
await waitPromise;
} catch (error) {
if (error instanceof JobCancelledError) {
console.log(`Job ${error.jobId} was cancelled`);
}
}
JobFailedError
Thrown when enqueueAndWait() encounters a job that failed.
Error message including job ID and original error message
Original error message from the job handler
Error class name: 'JobFailedError'
When thrown:
enqueueAndWait() waits for a job that fails permanently
- Different from
MaxRetriesError - this wraps the serialized error message
import { JobFailedError } from '@platformatic/job-queue'
try {
const result = await queue.enqueueAndWait(
{ userId: 'invalid-id' },
{ timeout: 10000 }
);
} catch (error) {
if (error instanceof JobFailedError) {
console.error(`Job ${error.jobId} failed`);
console.error('Error from handler:', error.originalError);
}
}
Storage Errors
StorageError
Thrown when a storage operation fails.
Error message describing the storage failure
Error code: 'STORAGE_ERROR'
The underlying error from the storage backend
Error class name: 'StorageError'
When thrown:
- Redis connection failures
- File system errors (FileStorage)
- Network issues with storage backend
- Storage backend crashes or becomes unavailable
import { StorageError } from '@platformatic/job-queue'
import { RedisStorage } from '@platformatic/job-queue'
import Redis from 'ioredis'
const redis = new Redis({
host: 'localhost',
port: 6379,
retryStrategy: (times) => {
if (times > 3) return null; // Stop retrying
return Math.min(times * 100, 2000);
}
});
const queue = new Queue({
storage: new RedisStorage(redis)
});
try {
await queue.enqueue({ task: 'process-data' });
} catch (error) {
if (error instanceof StorageError) {
console.error('Storage operation failed:', error.message);
if (error.cause) {
console.error('Underlying error:', error.cause.message);
}
// Attempt reconnection or fallback
await handleStorageFailure(error);
}
}
// Also emitted as 'error' event
queue.on('error', (error) => {
if (error instanceof StorageError) {
console.error('Queue storage error:', error);
}
});
Error Handling Patterns
Comprehensive Error Handling
import {
JobQueueError,
TimeoutError,
MaxRetriesError,
JobCancelledError,
JobFailedError,
JobNotFoundError,
StorageError
} from '@platformatic/job-queue'
async function processWithErrorHandling(payload: any) {
try {
const result = await queue.enqueueAndWait(
payload,
{
timeout: 30000,
maxAttempts: 3
}
);
return result;
} catch (error) {
if (error instanceof TimeoutError) {
// Job timed out but may still complete
console.warn(`Job ${error.jobId} timed out, checking status later`);
scheduleStatusCheck(error.jobId);
throw error;
}
else if (error instanceof MaxRetriesError) {
// Job failed permanently
console.error(`Job failed after ${error.attempts} attempts`);
await notifyAdmin(error);
throw error;
}
else if (error instanceof JobCancelledError) {
// Job was cancelled
console.log(`Job ${error.jobId} was cancelled`);
return null;
}
else if (error instanceof JobFailedError) {
// Job failed with specific error
console.error(`Job failed: ${error.originalError}`);
throw error;
}
else if (error instanceof StorageError) {
// Storage backend issue
console.error('Storage error:', error.cause);
await alertOps(error);
throw error;
}
else if (error instanceof JobQueueError) {
// Other queue errors
console.error(`Queue error [${error.code}]: ${error.message}`);
throw error;
}
else {
// Unexpected error
console.error('Unexpected error:', error);
throw error;
}
}
}
Retry with Backoff
async function enqueueWithRetry(payload: any, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await queue.enqueue(payload);
} catch (error) {
if (error instanceof StorageError && i < retries - 1) {
// Wait with exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
continue;
}
throw error;
}
}
}
Graceful Degradation
async function enqueueOrFallback(payload: any) {
try {
await queue.enqueue(payload);
return { status: 'queued' };
} catch (error) {
if (error instanceof StorageError) {
// Fallback to synchronous processing
console.warn('Queue unavailable, processing synchronously');
const result = await processJobDirectly(payload);
return { status: 'completed', result };
}
throw error;
}
}