@bernierllc/retry-manager
v1.2.2
Published
Service layer for orchestrating retry operations with comprehensive state management, metrics collection, and configuration
Readme
@bernierllc/retry-manager
A comprehensive service layer for orchestrating retry operations with state management, metrics collection, and configuration management.
Overview
The @bernierllc/retry-manager package provides a high-level service that orchestrates the core retry packages (retry-policy, retry-state, and retry-metrics) to deliver enterprise-grade retry functionality with:
- Comprehensive orchestration of core retry packages
- State persistence with configurable storage backends
- Metrics collection and performance monitoring
- Flexible configuration with environment support
- Lifecycle management with graceful shutdown
- Health monitoring and diagnostics
Installation
npm install @bernierllc/retry-managerQuick Start
import { RetryManager } from '@bernierllc/retry-manager';
// Create retry manager with default configuration
const retryManager = new RetryManager();
// Execute a function with retries
const result = await retryManager.executeWithRetry(
'api-call-123',
async () => {
const response = await fetch('/api/data');
if (!response.ok) throw new Error('API request failed');
return response.json();
},
{
maxRetries: 3,
initialDelayMs: 1000,
backoffFactor: 2
}
);
if (result.success) {
console.log('Data retrieved:', result.data);
} else {
console.error('Failed after', result.attempts, 'attempts:', result.error);
}Configuration
Basic Configuration
import { RetryManager } from '@bernierllc/retry-manager';
const retryManager = new RetryManager({
// Default retry options for all operations
defaultOptions: {
maxRetries: 5,
initialDelayMs: 1000,
backoffFactor: 2,
maxDelayMs: 30000,
jitter: true
},
// Maximum concurrent retry operations
maxConcurrentRetries: 100,
// Cleanup interval for stale states
cleanupIntervalMs: 300000, // 5 minutes
// Enable/disable retry operations
enabled: true
});Advanced Configuration
import {
RetryManager,
MemoryRetryStateStorage,
MetricsCollector,
MemoryMetricsStorage
} from '@bernierllc/retry-manager';
const retryManager = new RetryManager({
// Custom storage backend
storage: new MemoryRetryStateStorage(),
// Custom metrics collector
metrics: new MetricsCollector({
storage: new MemoryMetricsStorage()
}),
// Custom logger
logger: {
debug: (msg, meta) => console.debug(msg, meta),
info: (msg, meta) => console.info(msg, meta),
warn: (msg, meta) => console.warn(msg, meta),
error: (msg, meta) => console.error(msg, meta)
},
defaultOptions: {
maxRetries: 3,
initialDelayMs: 500,
retryCondition: (error) => {
// Only retry on network or server errors
return error.message.includes('network') ||
error.message.includes('timeout') ||
error.message.includes('500');
},
onRetry: (attempt, delay, error) => {
console.log(`Retry ${attempt} in ${delay}ms due to: ${error.message}`);
},
onSuccess: (result, attempts) => {
console.log(`Operation succeeded after ${attempts} attempts`);
},
onFailure: (error, attempts) => {
console.error(`Operation failed after ${attempts} attempts: ${error.message}`);
}
}
});Core Features
Retry Execution
Execute functions with comprehensive retry logic:
// Basic retry
const result = await retryManager.executeWithRetry(
'unique-operation-id',
async () => {
// Your operation here
return await someAsyncOperation();
}
);
// With custom options
const result = await retryManager.executeWithRetry(
'custom-operation',
async () => someAsyncOperation(),
{
maxRetries: 5,
initialDelayMs: 2000,
backoffFactor: 1.5,
maxDelayMs: 10000,
jitter: true,
timeout: 30000,
metadata: {
type: 'api-call',
description: 'Critical data fetch'
}
}
);State Management
Monitor and manage retry operation states:
// Get operation state
const state = await retryManager.getState('operation-id');
if (state) {
console.log(`Operation status: ${state.status}`);
console.log(`Attempts made: ${state.attempts}`);
console.log(`Next retry at: ${state.nextRetryAt}`);
}
// List operations with filtering
const operations = await retryManager.listRetries({
status: 'running',
limit: 10,
sortBy: 'createdAt',
sortOrder: 'desc'
});
console.log(`Found ${operations.total} running operations`);
// Cancel operation
await retryManager.cancelRetry('operation-id');Metrics and Monitoring
Access comprehensive metrics and performance data:
// Get retry metrics
const metrics = await retryManager.getMetrics();
console.log(`Success rate: ${(metrics.successRate * 100).toFixed(1)}%`);
console.log(`Average attempts: ${metrics.averageAttempts.toFixed(1)}`);
console.log(`Total operations: ${metrics.totalRetries}`);
// Get performance statistics
const stats = retryManager.getPerformanceStats();
console.log(`Active operations: ${stats.activeRetries}`);
console.log(`Memory usage: ${(stats.memoryUsage / 1024 / 1024).toFixed(1)} MB`);
console.log(`Throughput: ${stats.throughput.toFixed(1)} ops/sec`);
// Health check
const health = await retryManager.getHealthStatus();
console.log(`System healthy: ${health.healthy}`);
console.log('Component health:', health.checks);Configuration Management
Update configuration at runtime:
// Update configuration
retryManager.updateConfig({
maxConcurrentRetries: 200,
defaultOptions: {
maxRetries: 7,
initialDelayMs: 500
}
});
// Get current configuration
const config = retryManager.getConfig();
console.log('Current max retries:', config.defaultOptions?.maxRetries);Error Handling
The package provides specific error types for different failure scenarios:
import {
RetryManagerError,
OrchestrationError,
RetryLimitExceededError,
OperationTimeoutError
} from '@bernierllc/retry-manager';
try {
const result = await retryManager.executeWithRetry('op-1', someFunction);
} catch (error) {
if (error instanceof RetryLimitExceededError) {
console.error(`Retry limit exceeded after ${error.attempts} attempts`);
} else if (error instanceof OperationTimeoutError) {
console.error(`Operation timed out after ${error.timeoutMs}ms`);
} else if (error instanceof OrchestrationError) {
console.error(`Orchestration error for ${error.retryId}: ${error.message}`);
}
}Advanced Usage
Custom Retry Conditions
const result = await retryManager.executeWithRetry(
'conditional-retry',
async () => apiCall(),
{
retryCondition: (error) => {
// Retry on specific HTTP status codes
if (error.name === 'HTTPError') {
const statusCode = error.statusCode;
return statusCode >= 500 || statusCode === 429; // Server errors or rate limiting
}
// Retry on network errors
return error.message.includes('network') ||
error.message.includes('timeout');
},
maxRetries: 5,
initialDelayMs: 1000,
backoffFactor: 2
}
);Operation Callbacks
await retryManager.executeWithRetry(
'callback-demo',
async () => riskyOperation(),
{
onRetry: (attempt, delay, error) => {
console.log(`[Attempt ${attempt}] Retrying in ${delay}ms due to: ${error.message}`);
// Send to monitoring system
monitoring.recordRetry({
operation: 'callback-demo',
attempt,
delay,
error: error.message
});
},
onSuccess: (result, attempts) => {
console.log(`✓ Operation succeeded after ${attempts} attempts`);
monitoring.recordSuccess('callback-demo', attempts);
},
onFailure: (error, attempts) => {
console.error(`✗ Operation failed permanently after ${attempts} attempts`);
monitoring.recordFailure('callback-demo', attempts, error.message);
}
}
);Batch Operations
// Execute multiple operations with retry
const operations = [
{ id: 'op-1', fn: () => fetchUserData(1) },
{ id: 'op-2', fn: () => fetchUserData(2) },
{ id: 'op-3', fn: () => fetchUserData(3) }
];
const results = await Promise.allSettled(
operations.map(op =>
retryManager.executeWithRetry(op.id, op.fn, {
maxRetries: 3,
initialDelayMs: 500
})
)
);
// Process results
results.forEach((result, index) => {
if (result.status === 'fulfilled' && result.value.success) {
console.log(`Operation ${operations[index].id} succeeded:`, result.value.data);
} else {
console.error(`Operation ${operations[index].id} failed`);
}
});Lifecycle Management
// Graceful shutdown
process.on('SIGTERM', async () => {
console.log('Shutting down gracefully...');
await retryManager.shutdown();
process.exit(0);
});
// Health checks for load balancers
app.get('/health', async (req, res) => {
const health = await retryManager.getHealthStatus();
res.status(health.healthy ? 200 : 503).json(health);
});Integration with Core Packages
This service package orchestrates these core @bernierllc packages:
- @bernierllc/retry-policy - Exponential backoff and jitter algorithms
- @bernierllc/retry-state - State management and persistence
- @bernierllc/retry-metrics - Metrics collection and analytics
Performance Considerations
- Minimal overhead: ~1ms orchestration overhead per operation
- Memory efficient: <5MB for 1000 active retry operations
- Configurable limits: Control concurrent operations and cleanup intervals
- Cleanup automation: Automatic removal of stale retry states
TypeScript Support
Full TypeScript support with comprehensive type definitions:
import type {
RetryManagerConfig,
RetryOptions,
RetryResult,
RetryMetrics,
PerformanceStats,
ListOptions,
Logger
} from '@bernierllc/retry-manager';License
Copyright (c) 2025 Bernier LLC. All rights reserved.
