@bernierllc/retry-state
v0.2.0
Published
Atomic retry state management utilities
Readme
@bernierllc/retry-state
Atomic retry state management utilities for the BernierLLC package suite.
Overview
@bernierllc/retry-state provides immutable, focused utilities for managing retry operation states. This package is designed to be used as a core dependency by other retry-related packages in the BernierLLC suite.
Features
- Immutable State Management: All state operations return new state objects
- Type Safety: Full TypeScript support with strict typing
- Storage Abstraction: Pluggable storage adapters (Memory, Redis)
- Validation: Built-in state validation with detailed error reporting
- Statistics: Comprehensive analytics and filtering utilities
- Zero Dependencies: Pure functions with no external runtime dependencies
Installation
npm install @bernierllc/retry-stateQuick Start
import {
createRetryState,
updateRetryState,
canRetry,
markAsCompleted
} from '@bernierllc/retry-state';
// Create a new retry state
const state = createRetryState({
id: 'my-operation',
maxRetries: 3,
initialDelayMs: 1000
});
// Check if operation can be retried
if (canRetry(state)) {
// Prepare for next attempt
const nextState = updateRetryState(state, {
attempt: state.attempt + 1,
status: 'retrying',
delay: 2000,
updateNextRetry: true
});
}
// Mark as completed
const completedState = markAsCompleted(state);API Reference
Core Functions
createRetryState(config: RetryStateConfig): RetryState
Creates a new retry state with the given configuration.
const state = createRetryState({
id: 'unique-operation-id',
maxRetries: 5,
initialDelayMs: 1000,
metadata: { userId: '123', operation: 'email-send' }
});updateRetryState(state: RetryState, updates: RetryStateUpdateOptions): RetryState
Creates a new retry state by applying updates to an existing one.
const updatedState = updateRetryState(state, {
attempt: 2,
status: 'retrying',
delay: 2000,
error: new Error('Network timeout'),
updateNextRetry: true
});validateRetryState(state: RetryState): RetryStateValidationResult
Validates a retry state for consistency and correctness.
const validation = validateRetryState(state);
if (!validation.isValid) {
console.error('Validation errors:', validation.errors);
}State Queries
canRetry(state: RetryState): boolean
Checks if a retry state can be retried.
hasExceededMaxAttempts(state: RetryState): boolean
Checks if a retry state has exceeded its maximum attempts.
isReadyForRetry(state: RetryState): boolean
Checks if a retry state is ready for the next retry attempt.
State Transitions
markAsCompleted(state: RetryState): RetryState
Marks a retry state as successfully completed.
markAsFailed(state: RetryState, error: Error): RetryState
Marks a retry state as failed with the given error.
markAsCancelled(state: RetryState): RetryState
Marks a retry state as cancelled.
prepareForNextAttempt(state: RetryState, newDelay: number): RetryState
Prepares a retry state for the next attempt with the given delay.
Time Utilities
getRetryStateAge(state: RetryState): number
Returns the age of a retry state in milliseconds.
getTimeSinceLastAttempt(state: RetryState): number | null
Returns the time since the last attempt in milliseconds.
getTimeUntilNextRetry(state: RetryState): number | null
Returns the time until the next retry in milliseconds.
Storage Adapters
MemoryRetryStateStorage
In-memory storage with LRU eviction.
import { MemoryRetryStateStorage } from '@bernierllc/retry-state';
const storage = new MemoryRetryStateStorage(1000); // Max 1000 states
await storage.set('operation-1', state);
const retrieved = await storage.get('operation-1');RedisRetryStateStorage
Redis storage with automatic fallback to memory.
import { RedisRetryStateStorage } from '@bernierllc/retry-state';
import Redis from 'ioredis';
const redis = new Redis();
const storage = new RedisRetryStateStorage(redis, 'retry:');createRetryStateStorage()
Factory function to create storage adapters.
import { createRetryStateStorage } from '@bernierllc/retry-state';
// Memory storage (default)
const memoryStorage = createRetryStateStorage();
// Redis storage
const redisStorage = createRetryStateStorage('redis', {
redisClient: redis,
prefix: 'my-app:retry:'
});Statistics and Analytics
calculateRetryStateStats(states: RetryState[]): RetryStateStats
Calculates comprehensive statistics for a collection of retry states.
const stats = calculateRetryStateStats(allStates);
console.log(`Success rate: ${(stats.completed / stats.total * 100).toFixed(1)}%`);filterRetryStatesByStatus(states: RetryState[], status: RetryStatus): RetryState[]
Filters retry states by their status.
filterRetryStatesByAge(states: RetryState[], minAgeMs?: number, maxAgeMs?: number): RetryState[]
Filters retry states by their age.
sortRetryStates(states: RetryState[], field: keyof RetryState, direction: 'asc' | 'desc'): RetryState[]
Sorts retry states by a specified field.
findReadyForRetry(states: RetryState[]): RetryState[]
Finds retry states that are ready for retry.
calculateSuccessRate(states: RetryState[]): number
Calculates the success rate as a percentage.
Types
RetryState
interface RetryState {
readonly id: string;
readonly attempt: number;
readonly maxRetries: number;
readonly status: RetryStatus;
readonly lastAttempt: Date | null;
readonly nextRetry: Date | null;
readonly delay: number;
readonly error?: Error | null;
readonly metadata?: Record<string, unknown>;
readonly createdAt: Date;
readonly updatedAt: Date;
}RetryStatus
type RetryStatus = 'pending' | 'retrying' | 'completed' | 'failed' | 'cancelled';RetryStateConfig
interface RetryStateConfig {
id: string;
maxRetries: number;
initialDelayMs: number;
metadata?: Record<string, unknown>;
}RetryStateStorage
interface RetryStateStorage {
get(id: string): Promise<RetryState | null>;
set(id: string, state: RetryState): Promise<void>;
delete(id: string): Promise<void>;
list(prefix?: string): Promise<RetryState[]>;
clear(): Promise<void>;
exists(id: string): Promise<boolean>;
}Examples
Basic Retry Loop
import {
createRetryState,
canRetry,
prepareForNextAttempt,
markAsCompleted,
markAsFailed
} from '@bernierllc/retry-state';
async function executeWithRetry<T>(
id: string,
operation: () => Promise<T>
): Promise<T> {
let state = createRetryState({
id,
maxRetries: 3,
initialDelayMs: 1000
});
while (canRetry(state)) {
try {
const result = await operation();
state = markAsCompleted(state);
return result;
} catch (error) {
if (state.attempt >= state.maxRetries) {
state = markAsFailed(state, error);
throw error;
}
const delay = state.delay * 2; // Exponential backoff
state = prepareForNextAttempt(state, delay);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Max retries exceeded');
}Persistent Storage
import {
createRetryStateStorage,
createRetryState,
updateRetryState
} from '@bernierllc/retry-state';
const storage = createRetryStateStorage('memory');
async function resumeRetry(id: string) {
// Try to get existing state
let state = await storage.get(id);
if (!state) {
// Create new state if none exists
state = createRetryState({
id,
maxRetries: 5,
initialDelayMs: 1000
});
}
// Update and persist state
state = updateRetryState(state, { status: 'retrying' });
await storage.set(id, state);
return state;
}Analytics Dashboard
import {
calculateRetryStateStats,
filterRetryStatesByStatus,
calculateSuccessRate
} from '@bernierllc/retry-state';
async function generateRetryAnalytics() {
const allStates = await storage.list();
const stats = calculateRetryStateStats(allStates);
const pendingStates = filterRetryStatesByStatus(allStates, 'pending');
const successRate = calculateSuccessRate(allStates);
return {
total: stats.total,
pending: stats.pending,
successRate: `${successRate.toFixed(1)}%`,
averageAttempts: stats.averageAttempts.toFixed(2)
};
}Testing
npm test
npm run test:coverageContributing
This package follows the BernierLLC development standards:
- All code must be written in TypeScript with strict mode enabled
- Tests must achieve 90%+ coverage
- No external runtime dependencies
- Comprehensive documentation for all public APIs
License
MIT License - see LICENSE for details.
Related Packages
@bernierllc/retry-policy- Retry policy algorithms and utilities@bernierllc/retry-manager- High-level retry orchestration (coming soon)@bernierllc/retry-suite- Complete retry system (coming soon)
