UNPKG

@types/opossum

Version:
444 lines (384 loc) 15.6 kB
/// <reference types="node"/> import { EventEmitter } from "events"; declare class CircuitBreaker<TI extends unknown[] = unknown[], TR = unknown> extends EventEmitter { static isOurError(error: Error): boolean; static newStatus(options: CircuitBreaker.StatusOptions): CircuitBreaker.Status; constructor(action: (...args: TI) => Promise<TR>, options?: CircuitBreaker.Options<TI>); /** * Gets the name of this circuit */ readonly name: string; /** * Gets the name of this circuit group */ readonly group: string; /** * Gets whether the circuit is enabled or not */ readonly enabled: boolean; /** * Gets whether this circuit is in the pendingClosed state */ readonly pendingClose: boolean; /** * True if the circuit is currently closed. False otherwise. */ readonly closed: boolean; /** * True if the circuit is currently opened. False otherwise. */ readonly opened: boolean; /** * True if the circuit is currently half opened. False otherwise. */ readonly halfOpen: boolean; /** * Determines if the circuit has been shutdown. */ readonly isShutdown: boolean; /** * The current {@link CircuitBreaker.Status} of this {@link CircuitBreaker} */ readonly status: CircuitBreaker.Status; /** * Get the current stats for the circuit. */ readonly stats: CircuitBreaker.Stats; /** * Gets whether the circuit is currently in warm up phase */ readonly warmUp: boolean; /** * Gets the volume threshold for this circuit */ readonly volumeThreshold: number; /** * Execute the action for this circuit using context as this. * If the action fails or times out, the returned promise will be rejected. * If the action succeeds, the promise will resolve with the resolved value from action. * If a fallback function was provided, it will be invoked in the event of any failure or timeout. * Any parameters in addition to `context` will be passed to the circuit function. */ call(context: any, ...args: TI): Promise<TR>; /** * Returns the current state of the circuit */ toJSON(): { state: CircuitBreaker.State; status: CircuitBreaker.Stats }; /** * Clears the cache of this {@link CircuitBreaker} */ clearCache(): void; /** * Closes the breaker, allowing the action to execute again */ close(): void; /** * Opens the breaker. * Each time the breaker is fired while the circuit is opened, a failed Promise is * returned, or if any fallback function has been provided, it is invoked. */ open(): void; /** * Shuts down this circuit breaker. * All subsequent calls to the circuit will fail, returning a rejected promise. */ shutdown(): void; /** * Disables this circuit, causing all calls to the circuit's function to be * executed without circuit or fallback protection. */ disable(): void; /** * Enables this circuit. If the circuit is the disabled state, it will be re-enabled. * If not, this is essentially a noop. */ enable(): void; /** * Provide a fallback function for this {@link CircuitBreaker}. * This function will be executed when the circuit is fired and fails. * It will always be preceded by a `failure` event, and `breaker.fire` returns a rejected Promise. */ fallback(func: ((...args: any[]) => any) | CircuitBreaker): this; /** * Execute the action for this circuit. * If the action fails or times out, the returned promise will be rejected. * If the action succeeds, the promise will resolve with the resolved value from action. * If a fallback function was provided, it will be invoked in the event of any failure or timeout. * Any parameters passed to this function will be proxied to the circuit function. */ fire(...args: TI): Promise<TR>; /** * Provide a health check function to be called periodically. * The function should return a Promise. If the promise is rejected the circuit will open. * This is in addition to the existing circuit behavior as defined by the * `errorThresholdPercentage` option passed to the constructor. * For example, if the health check function provided here always returns a resolved promise, * the circuit can still trip and open if there are failures exceeding the configured threshold. * The health check function is executed within the circuit breaker's execution context, * so this within the function is the circuit breaker itself. * * The interval is the amount of time between calls to the health check function. * Default: 5000 (5 seconds) */ healthCheck(func: () => Promise<void>, interval?: number): void; /** * Emitted after `options.resetTimeout` has elapsed, allowing for a single attempt to call the service again. * If that attempt is successful, the circuit will be closed. Otherwise it remains open. */ on(event: "halfOpen", listener: (resetTimeout: number) => void): this; /** * Emitted when the breaker is reset allowing the action to execute again. */ on(event: "close", listener: () => void): this; /** * Emitted when the breaker opens because the action has failure percentage greater than `options.errorThresholdPercentage`. */ on(event: "open", listener: () => void): this; /** * Emitted when the circuit breaker has been shut down. */ on(event: "shutdown", listener: () => void): this; /** * Emitted when the circuit breaker action is executed. */ on(event: "fire", listener: (args: TI) => void): this; /** * Emitted when the circuit breaker is using the cache and finds a value. */ on(event: "cacheHit", listener: () => void): this; /** * Emitted when the circuit breaker does not find a value in the cache, but the cache option is enabled. */ on(event: "cacheMiss", listener: () => void): this; /** * Emitted when the circuit breaker is open and failing fast. */ on(event: "reject", listener: (err: Error) => void): this; /** * Emitted when the circuit breaker action takes longer than `options.timeout`. */ on(event: "timeout", listener: (err: Error) => void): this; /** * Emitted when the circuit breaker action succeeds. */ on(event: "success", listener: (result: TR, latencyMs: number) => void): this; /** * Emitted when the rate limit has been reached and there are no more locks to be obtained. */ on(event: "semaphoreLocked", listener: (err: Error) => void): this; /** * Emitted with the user-supplied health check function returns a rejected promise. */ on(event: "healthCheckFailed", listener: (err: Error) => void): this; /** * Emitted when the circuit breaker executes a fallback function. */ on(event: "fallback", listener: (result: unknown, err: Error) => void): this; /** * Emitted when the circuit breaker action fails. */ on(event: "failure", listener: (err: Error, latencyMs: number, args: TI) => void): this; } declare namespace CircuitBreaker { interface Options<TI extends unknown[] = unknown[]> { /** * A {@link Status} object that might have pre-prime stats */ status?: Status | undefined; /** * The time in milliseconds that action should be allowed to execute before timing out. * Timeout can be disabled by setting this to `false`. * @default 10000 (10 seconds) */ timeout?: number | false | undefined; /** * The number of times the circuit can fail before opening. * @default 10 * @deprecated * @see {@link Options.errorThresholdPercentage} */ maxFailures?: number | undefined; /** * The time in milliseconds to wait before setting the breaker to `halfOpen` state, and trying the action again. * @default 30000 (30 seconds) */ resetTimeout?: number | undefined; /** * Sets the duration of the statistical rolling window, in milliseconds. * This is how long Opossum keeps metrics for the circuit breaker to use and for publishing. * @default 10000 */ rollingCountTimeout?: number | undefined; /** * Sets the number of buckets the rolling statistical window is divided into. * So, if `options.rollingCountTimeout` is 10,000, and `options.rollingCountBuckets` is 10, then the * statistical window will be 1,000 per 1 second snapshots in the statistical window. * @default 10 */ rollingCountBuckets?: number | undefined; /** * The circuit name to use when reporting stats. * Defaults to the name of the function this circuit controls then falls back to a UUID */ name?: string | undefined; /** * (Undocumented) * A grouping key for reporting. * Defaults to the computed value of `name` */ group?: string | undefined; /** * This property indicates whether execution latencies should be tracked and calculated as percentiles. * If they are disabled, all summary statistics (mean, percentiles) are returned as -1. * @default false */ rollingPercentilesEnabled?: boolean | undefined; /** * The number of concurrent requests allowed. * If the number currently executing function calls is equal to `options.capacity`, further calls * to `fire()` are rejected until at least one of the current requests completes. * @default Number.MAX_SAFE_INTEGER */ capacity?: number | undefined; /** * The error percentage at which to open the circuit and start short-circuiting requests to fallback. * @default 50 */ errorThresholdPercentage?: number | undefined; /** * Whether this circuit is enabled upon construction. * @default true */ enabled?: boolean | undefined; /** * Determines whether to allow failures without opening the circuit during a brief warmup period (`rollingCountTimeout`) * This can help in situations where no matter what your `errorThresholdPercentage` is, if the * first execution times out or fails, the circuit immediately opens. * @default false */ allowWarmUp?: boolean | undefined; /** * The minimum number of requests within the rolling statistical window that must exist before * the circuit breaker can open. This is similar to `allowWarmUp` in that no matter how many * failures there are, if the number of requests within the statistical window does not exceed * this threshold, the circuit will remain closed. * @default 0 */ volumeThreshold?: number | undefined; /** * An optional function that will be called when the circuit's function fails (returns a rejected Promise). * If this function returns truthy, the circuit's `failPure` statistics will not be incremented. * This is useful, for example, when you don't want HTTP 404 to trip the circuit, but still want to handle it as a failure case. */ errorFilter?: ((err: any) => boolean) | undefined; /** * Whether the return value of the first successful execution of the circuit's function will be cached. * Once a value has been cached that value will be returned for every subsequent execution: the cache can be cleared using `clearCache`. * (The metrics cacheHit and cacheMiss reflect cache activity.) * @default false */ cache?: boolean | undefined; /** * The cache time to live (TTL) in milliseconds. * The default value is 0, which means the cache will never be cleared. * @default 0 (no TTL) */ cacheTTL?: number; /** * An optional function that will be called to generate a cache key for the circuit's function. * The function is passed the original `fire` arguments. If no `cacheKey` function is supplied, a `JSON.stringify` of the arguments will be used as the key. * @default (...args) => JSON.stringify(args) */ cacheGetKey?: ((...args: TI) => string) | undefined; /** * Transport for cache storage. By default, the cache is stored in memory. * If a cacheTransport is provided, the cache will be stored there instead. */ cacheTransport?: CacheTransport | undefined; /** * If present, Opossum can signal upon timeout and properly abort your on going requests instead of leaving it in the background. */ abortController?: AbortController | undefined; /** * Whether to enable the periodic snapshots that are emitted by the Status class. * Passing false will result in snapshots not being emitted * @default true */ enableSnapshots?: boolean | undefined; /** * Optional EventEmitter to be passed in to control the buckets instead of the bucket-interval timer */ rotateBucketController?: EventEmitter | undefined; } interface Status extends EventEmitter { stats: Stats; window: Window; on(event: "snapshot", listener: (snapshot: Stats) => void): this; } interface StatusOptions extends Pick< CircuitBreaker.Options, | "rollingCountBuckets" | "rollingCountTimeout" | "rollingPercentilesEnabled" | "enableSnapshots" | "rotateBucketController" > { /** * object of previous stats */ stats?: Stats; } interface Bucket { failures: number; fallbacks: number; successes: number; rejects: number; fires: number; timeouts: number; cacheHits: number; cacheMisses: number; semaphoreRejections: number; percentiles: { [percentile: number]: number }; latencyTimes: number[]; } type Window = Bucket[]; interface Stats extends Bucket { latencyMean: number; } interface State { name: string; enabled: boolean; closed: boolean; open: boolean; halfOpen: boolean; warmUp: boolean; shutdown: boolean; lastTimerAt: symbol; } /** * Simple in-memory cache implementation */ interface MemoryCache { /** * Get cache value by key * @param {string} key Cache key * @returns Response from cache */ get(key: string): unknown | undefined; /** * Set cache key with value and ttl * @param {string} key Cache key * @param {any} value Value to cache * @param {number} ttl Time to live in milliseconds */ set(key: string, value: any, ttl: number): void; /** * Clear cache */ flush(): void; } type CacheTransport = MemoryCache; } export = CircuitBreaker;