@zerothrow/resilience
Version:
Production-grade resilience patterns for ZeroThrow
164 lines (154 loc) • 6.02 kB
text/typescript
import { Result } from '@zerothrow/core';
interface Policy$1 {
execute<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
}
interface RetryPolicy$1 extends Policy$1 {
onRetry(callback: (attempt: number, error: unknown, delay: number) => void): RetryPolicy$1;
}
interface CircuitBreakerPolicy$1 extends Policy$1 {
onCircuitStateChange(callback: (state: 'open' | 'closed' | 'half-open') => void): CircuitBreakerPolicy$1;
}
type TimeoutPolicy$1 = Policy$1;
type AnyPolicy = RetryPolicy$1 | CircuitBreakerPolicy$1 | TimeoutPolicy$1 | Policy$1;
interface RetryOptions {
backoff?: 'constant' | 'linear' | 'exponential';
delay?: number;
maxDelay?: number;
handle?: (error: Error) => boolean;
}
interface CircuitOptions {
threshold: number;
duration: number;
onOpen?: () => void;
onClose?: () => void;
}
interface TimeoutOptions {
timeout: number;
}
interface PolicyError extends Error {
type: PolicyErrorType;
policyName: string;
context?: unknown;
}
type PolicyErrorType = 'retry-exhausted' | 'circuit-open' | 'timeout';
declare class RetryExhaustedError extends Error implements PolicyError {
readonly policyName: string;
readonly attempts: number;
readonly lastError: Error;
readonly context?: unknown | undefined;
readonly type: "retry-exhausted";
constructor(policyName: string, attempts: number, lastError: Error, context?: unknown | undefined);
}
declare class CircuitOpenError extends Error implements PolicyError {
readonly policyName: string;
readonly openedAt: Date;
readonly failureCount: number;
readonly context?: unknown | undefined;
readonly type: "circuit-open";
constructor(policyName: string, openedAt: Date, failureCount: number, context?: unknown | undefined);
}
declare class TimeoutError extends Error implements PolicyError {
readonly policyName: string;
readonly timeout: number;
readonly elapsed: number;
readonly context?: unknown | undefined;
readonly type: "timeout";
constructor(policyName: string, timeout: number, elapsed: number, context?: unknown | undefined);
}
interface Clock {
now(): Date;
sleep(ms: number): Promise<void>;
}
declare class SystemClock implements Clock {
now(): Date;
sleep(ms: number): Promise<void>;
}
declare class TestClock implements Clock {
private currentTime;
private sleepers;
now(): Date;
sleep(ms: number): Promise<void>;
advance(ms: number): void;
setTime(time: Date | number): void;
}
declare abstract class BasePolicy implements Policy$1 {
protected readonly name: string;
protected readonly clock: Clock;
constructor(name: string, clock?: Clock);
abstract execute<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
protected runOperation<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
}
declare class RetryPolicy extends BasePolicy implements RetryPolicy$1 {
private readonly count;
private readonly options;
private retryCallback?;
constructor(count: number, options?: RetryOptions, clock?: Clock);
execute<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
onRetry(callback: (attempt: number, error: unknown, delay: number) => void): RetryPolicy$1;
private calculateDelay;
}
type CircuitState = 'closed' | 'open' | 'half-open';
declare class CircuitBreakerPolicy extends BasePolicy implements CircuitBreakerPolicy$1 {
private readonly options;
private state;
private failures;
private lastFailureTime?;
private nextAllowedTime?;
private stateChangeCallback?;
constructor(options: CircuitOptions, clock?: Clock);
execute<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
private onSuccess;
private onFailure;
private open;
private reset;
private setState;
onCircuitStateChange(callback: (state: CircuitState) => void): CircuitBreakerPolicy$1;
}
declare class TimeoutPolicy extends BasePolicy {
private readonly options;
constructor(options: TimeoutOptions, clock?: Clock);
execute<T>(operation: () => Promise<T>): Promise<Result<T, Error>>;
}
/**
* Wraps one policy with another, creating a composed policy.
* The outer policy executes first and passes its operation to the inner policy.
*
* Example: Policy.wrap(retry, timeout) creates a policy that retries with timeouts
*/
declare function wrap(outer: Policy$1, inner: Policy$1): Policy$1;
/**
* Composes multiple policies from left to right.
* The leftmost policy is the outermost wrapper.
*
* Example: compose(retry, circuit, timeout)
* Results in: retry wraps (circuit wraps (timeout wraps operation))
*/
declare function compose(...policies: Policy$1[]): Policy$1;
/**
* Main factory for creating resilience policies
*/
declare const Policy: {
/**
* Creates a retry policy
*/
readonly retry: (count: number, options?: RetryOptions, clock?: Clock) => RetryPolicy;
/**
* Creates a circuit breaker policy
*/
readonly circuitBreaker: (options: CircuitOptions, clock?: Clock) => CircuitBreakerPolicy;
/**
* Creates a timeout policy
*/
readonly timeout: (options: TimeoutOptions | number, clock?: Clock) => TimeoutPolicy;
/**
* Wraps one policy with another
* The outer policy executes first
*/
readonly wrap: typeof wrap;
/**
* Composes multiple policies from left to right
* The leftmost policy is the outermost wrapper
*/
readonly compose: typeof compose;
};
export { type AnyPolicy, CircuitBreakerPolicy, type CircuitBreakerPolicy$1 as CircuitBreakerPolicyInterface, CircuitOpenError, type CircuitOptions, type Clock, type Policy$1 as Policy, type PolicyError, type PolicyErrorType, Policy as PolicyFactory, RetryExhaustedError, type RetryOptions, RetryPolicy, type RetryPolicy$1 as RetryPolicyInterface, SystemClock, TestClock, TimeoutError, type TimeoutOptions, TimeoutPolicy, type TimeoutPolicy$1 as TimeoutPolicyInterface, compose, wrap };