@bernierllc/retry-policy
v0.1.6
Published
Atomic retry policy utilities with exponential backoff and jitter
Readme
@bernierllc/retry-policy
Atomic retry policy utilities with exponential backoff and jitter support.
Overview
@bernierllc/retry-policy provides atomic utilities for implementing retry logic with configurable backoff strategies and jitter. This package is designed to be a core building block that can be used by higher-level retry managers and services.
Features
- Multiple backoff strategies: Exponential, linear, and constant backoff
- Configurable jitter: Full, equal, decorrelated, and no jitter options
- Custom retry conditions: Flexible error evaluation logic
- Type-safe API: Full TypeScript support with strict typing
- Zero dependencies: Pure functions with no external dependencies
- Comprehensive testing: 95%+ test coverage
Installation
npm install @bernierllc/retry-policyQuick Start
import { RetryPolicy, createRetryPolicy } from '@bernierllc/retry-policy';
// Create a retry policy with default settings
const policy = new RetryPolicy();
// Evaluate if an operation should be retried
const result = policy.evaluateRetry(1, new Error('Network error'));
console.log(result);
// {
// shouldRetry: true,
// delay: 2000,
// attempt: 1,
// isFinalAttempt: false
// }API Reference
RetryPolicy Class
The main class for managing retry policies.
Constructor
new RetryPolicy(options?: Partial<RetryPolicyOptions>, backoffConfig?: Partial<BackoffConfig>)Methods
evaluateRetry(attempt: number, error: any): RetryPolicyResultcalculateDelay(attempt: number): numbergetOptions(): Required<RetryPolicyOptions>getBackoffConfig(): BackoffConfigupdateOptions(options: Partial<RetryPolicyOptions>): voidupdateBackoffConfig(config: Partial<BackoffConfig>): void
Utility Functions
createRetryPolicy(options?, backoffConfig?): RetryPolicycalculateRetryDelay(attempt, options?, backoffConfig?): numbershouldRetry(attempt, error, options?): boolean
Usage Examples
Basic Usage
import { RetryPolicy } from '@bernierllc/retry-policy';
const policy = new RetryPolicy({
maxRetries: 3,
initialDelayMs: 1000,
shouldRetry: (error) => error.code === 'NETWORK_ERROR'
});
// In your retry loop
for (let attempt = 0; attempt <= 3; attempt++) {
try {
const result = await someOperation();
break; // Success, exit retry loop
} catch (error) {
const retryResult = policy.evaluateRetry(attempt, error);
if (!retryResult.shouldRetry) {
throw error; // Don't retry, re-throw error
}
// Wait before next attempt
await new Promise(resolve => setTimeout(resolve, retryResult.delay));
}
}Custom Backoff Strategy
import { RetryPolicy } from '@bernierllc/retry-policy';
const policy = new RetryPolicy(
{ maxRetries: 5 },
{
type: 'exponential',
baseDelay: 500,
factor: 3,
maxDelay: 10000,
jitter: {
type: 'full',
factor: 0.1
}
}
);
// This will use exponential backoff with full jitter
const delay = policy.calculateDelay(2); // ~4500ms with jitterDifferent Backoff Types
import { RetryPolicy } from '@bernierllc/retry-policy';
// Exponential backoff (default)
const exponential = new RetryPolicy(undefined, {
type: 'exponential',
baseDelay: 1000,
factor: 2
});
// Delays: 1000ms, 2000ms, 4000ms, 8000ms...
// Linear backoff
const linear = new RetryPolicy(undefined, {
type: 'linear',
baseDelay: 1000
});
// Delays: 1000ms, 2000ms, 3000ms, 4000ms...
// Constant backoff
const constant = new RetryPolicy(undefined, {
type: 'constant',
baseDelay: 1000
});
// Delays: 1000ms, 1000ms, 1000ms, 1000ms...Jitter Types
import { RetryPolicy } from '@bernierllc/retry-policy';
// Full jitter: random value between 0 and delay
const fullJitter = new RetryPolicy(undefined, {
jitter: { type: 'full', factor: 0.1 }
});
// Equal jitter: random value between delay/2 and delay
const equalJitter = new RetryPolicy(undefined, {
jitter: { type: 'equal', factor: 0.1 }
});
// Decorrelated jitter: random value between delay and delay * 3
const decorrelatedJitter = new RetryPolicy(undefined, {
jitter: { type: 'decorrelated', factor: 0.1 }
});
// No jitter: exact delay values
const noJitter = new RetryPolicy(undefined, {
jitter: { type: 'none' }
});Custom Retry Conditions
import { RetryPolicy } from '@bernierllc/retry-policy';
const policy = new RetryPolicy({
maxRetries: 5,
shouldRetry: (error) => {
// Only retry on network errors or 5xx server errors
if (error.code === 'NETWORK_ERROR') return true;
if (error.status >= 500 && error.status < 600) return true;
return false;
},
onRetry: (attempt, delay, error) => {
console.log(`Retry attempt ${attempt} after ${delay}ms due to:`, error.message);
},
onFailure: (error) => {
console.log('All retry attempts exhausted:', error.message);
}
});Configuration
RetryPolicyOptions
interface RetryPolicyOptions {
maxRetries: number; // Maximum number of retry attempts
initialDelayMs: number; // Initial delay in milliseconds
maxDelayMs?: number; // Maximum delay in milliseconds
backoffFactor?: number; // Exponential backoff factor
jitter?: boolean; // Whether to apply jitter
shouldRetry?: (error: any) => boolean; // Custom retry condition
onRetry?: (attempt: number, delay: number, error: any) => void; // Retry callback
onFailure?: (error: any) => void; // Failure callback
}BackoffConfig
interface BackoffConfig {
type: 'exponential' | 'linear' | 'constant'; // Backoff strategy
baseDelay: number; // Base delay in milliseconds
maxDelay: number; // Maximum delay in milliseconds
factor?: number; // Backoff factor for exponential
jitter?: JitterConfig; // Jitter configuration
}JitterConfig
interface JitterConfig {
type: 'none' | 'full' | 'equal' | 'decorrelated'; // Jitter type
factor?: number; // Jitter factor (0-1)
}Default Values
const DEFAULT_RETRY_OPTIONS = {
maxRetries: 5,
initialDelayMs: 1000,
maxDelayMs: 30000,
backoffFactor: 2,
jitter: true,
shouldRetry: () => true,
onRetry: () => {},
onFailure: () => {}
};
const DEFAULT_BACKOFF_CONFIG = {
type: 'exponential',
baseDelay: 1000,
maxDelay: 30000,
factor: 2,
jitter: { type: 'full', factor: 0.1 }
};Integration Status
Logger Integration
Status: not-applicable
This is a pure utility core package with no dependencies. Logging is handled by consuming packages. Does not require @bernierllc/logger integration.
Docs-Suite Integration
Status: ready
Complete API documentation with TypeScript types and examples available for documentation suite integration.
NeverHub Integration
Status: not-applicable
Pure utility package with no runtime dependencies. NeverHub integration is handled at the service-level packages that consume this utility. Does not require @bernierllc/neverhub-adapter integration.
Security
This package has zero runtime dependencies and uses only pure TypeScript functions. Security considerations:
- No External Dependencies: All retry logic is implemented internally with no external packages at runtime
- Type Safety: Strict TypeScript typing prevents common runtime errors
- No Network Calls: Pure computational functions with no I/O operations
- No Secret Storage: Does not handle or store any sensitive data
- Audit Clean:
npm auditshows no vulnerabilities (zero dependencies)
For security concerns, please open an issue in the repository.
Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watchContributing
This package follows the Bernier LLC development standards:
- TypeScript strict mode - All code must pass strict type checking
- Comprehensive testing - 95%+ test coverage required
- Documentation - All public APIs must be documented
- Code style - Follow project ESLint configuration
License
ISC License - see LICENSE file for details.
Related Packages
@bernierllc/retry-state- Retry state management and persistence@bernierllc/retry-metrics- Retry performance metrics collection@bernierllc/retry-manager- High-level retry orchestration service
