Configure retry strategies for resilient task execution with TypeScript
maxRetries
import { HyrexRegistry } from '@hyrex/hyrex'; const hy = new HyrexRegistry(); const resilientTask = hy.task({ name: 'resilientTask', config: { maxRetries: 3 // Retry up to 3 times on failure (0-10) }, func: async (data) => { // Task that might fail transiently const result = await unreliableService.call(data); return result; } });
// Task with retries will automatically use exponential backoff const apiTask = hy.task({ name: 'apiTask', config: { maxRetries: 5, timeoutSeconds: 30 }, func: async (data) => { // Failures will retry with increasing delays const response = await externalAPI.post(data); return response.data; } });
class RetryableError extends Error {} class PermanentError extends Error {} const smartTask = hy.task({ name: 'smartTask', config: { maxRetries: 3 }, func: async (data) => { try { return await riskyOperation(data); } catch (error: any) { if (error.code === 'RATE_LIMIT') { // This will retry with backoff throw new RetryableError('Rate limited, will retry'); } else if (error.code === 'INVALID_INPUT') { // This will still retry (but probably fail again) // Consider returning an error instead throw new PermanentError('Invalid input, retry won't help'); } // Unknown errors also retry throw error; } } });
const flexibleTask = hy.task({ name: 'flexibleTask', config: { maxRetries: 3 }, func: async (data) => { try { const result = await operation(data); return { success: true, result }; } catch (error) { // Option 1: Throw to trigger retry if (isTransient(error)) { throw error; // Will retry } // Option 2: Return error to complete task return { success: false, error: error.message, permanent: true // Won't retry }; } } });
import { getHyrexContext } from '@hyrex/hyrex'; const adaptiveTask = hy.task({ name: 'adaptiveTask', config: { maxRetries: 3 }, func: async (data) => { const ctx = getHyrexContext(); const attemptNumber = ctx.attemptNumber; // 0-based console.log(`Attempt ${attemptNumber + 1} of ${ctx.maxRetries + 1}`); // Use different strategies based on attempt if (attemptNumber === 0) { // First attempt - try primary service return await primaryService.process(data); } else if (attemptNumber < ctx.maxRetries) { // Intermediate attempts - try backup service return await backupService.process(data); } else { // Final attempt - use fallback return await fallbackProcessing(data); } } });
const apiCallTask = hy.task({ name: 'apiCall', config: { maxRetries: 5, timeoutSeconds: 30 }, func: async ({ endpoint, payload }) => { try { const response = await fetch(endpoint, { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { // Non-2xx status codes will retry throw new Error(`API error: ${response.status}`); } return await response.json(); } catch (error) { // Network errors, timeouts, etc. will retry console.error(`API call failed: ${error.message}`); throw error; } } });
const dbTask = hy.task({ name: 'dbOperation', config: { maxRetries: 2, // Fewer retries for DB operations queue: 'database' }, func: async ({ query, params }) => { try { return await db.execute(query, params); } catch (error) { if (error.code === 'DEADLOCK_DETECTED') { // Deadlocks are retryable throw error; } else if (error.code === 'CONSTRAINT_VIOLATION') { // Don't retry constraint violations return { error: 'Constraint violation', code: error.code, failed: true }; } throw error; } } });
const fileTask = hy.task({ name: 'processFile', config: { maxRetries: 3, timeoutSeconds: 300 // 5 minutes }, func: async ({ fileUrl }) => { const ctx = getHyrexContext(); try { // Download file const file = await downloadFile(fileUrl); // Process file const result = await processFile(file); // Cleanup await cleanup(file); return result; } catch (error) { // Log attempt for debugging console.error( `File processing failed on attempt ${ctx.attemptNumber + 1}:`, error.message ); // Always cleanup on failure await cleanup(file).catch(() => {}); throw error; // Retry } } });
// Quick operations: fewer retries config: { maxRetries: 2 } // External services: more retries config: { maxRetries: 5 } // Critical operations: max retries config: { maxRetries: 10 }
const idempotentTask = hy.task({ name: 'chargePayment', config: { maxRetries: 3, idempotencyKey: 'payment-123' // Prevents duplicate charges }, func: async (data) => { // Safe to retry without side effects return await paymentGateway.charge(data); } });
const loggingTask = hy.task({ name: 'withLogging', config: { maxRetries: 3 }, func: async (data) => { const ctx = getHyrexContext(); if (ctx.attemptNumber > 0) { console.log(`Retry attempt ${ctx.attemptNumber} for task ${ctx.taskId}`); } try { return await operation(data); } catch (error) { console.error(`Attempt ${ctx.attemptNumber} failed:`, error); throw error; } } });
const gracefulTask = hy.task({ name: 'gracefulFailure', config: { maxRetries: 3 }, func: async (data) => { const ctx = getHyrexContext(); try { return await riskyOperation(data); } catch (error) { // On final attempt, return error state if (ctx.attemptNumber === ctx.maxRetries) { await notifyFailure(ctx.taskId, error); return { status: 'failed_permanently', error: error.message, attempts: ctx.attemptNumber + 1 }; } throw error; // Retry } } });
Was this page helpful?