UNPKG

@newdash/newdash

Version:

javascript/typescript utility library

83 lines (82 loc) 2.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.circuit = exports.TemporaryUnAvailableError = void 0; /* eslint-disable max-len */ const assert_1 = require("../assert"); const cacheProvider_1 = require("../cacheProvider"); const functionWrapper_1 = require("../functional/functionWrapper"); const toHashCode_1 = require("../functional/toHashCode"); /** * TemporaryUnAvailableError * * when the circuit breaker is open (failure happened latest), will direct throw this error * * @internal please do not throw this error outside of newdash inner functions */ class TemporaryUnAvailableError extends Error { /** * the error cause the function temporary not available */ causeError; constructor(msg, causeError) { if (causeError !== undefined) { super(`${msg} cause error message(${causeError.message})`); } else { super(msg); } this.causeError = causeError; } } exports.TemporaryUnAvailableError = TemporaryUnAvailableError; /** * * @ignore * @private * @internal * @param error * @param key * @param breakerOpenTimers * @param breakerOpenReason */ function errorWithCircuit(error, key, breakerOpenTimers, breakerOpenReason) { if (!(error instanceof TemporaryUnAvailableError)) { breakerOpenTimers.set(key, Date.now()); breakerOpenReason.set(key, error); } throw error; } /** * fallback to circuit * * will directly raise error [[TemporaryUnAvailableError]] when some error happened before in duration * * @category Fallback * @param runner * @param openDuration default is 10000 (10 seconds) * @param cacheSize the timer & error cache size, default is 1024 */ function circuit(runner, openDuration = 10 * 1000, cacheSize = 1024) { (0, assert_1.mustProvide)(runner, "runner", "function"); (0, assert_1.mustProvide)(openDuration, "openDuration", "number"); if (openDuration === 0) { return runner; } const funcName = runner["name"] || "Unknown"; return (0, functionWrapper_1.createFunctionWrapper)(runner, { global: { breakerOpenTimers: new cacheProvider_1.LRUCacheProvider(cacheSize), breakerOpenReason: new cacheProvider_1.LRUCacheProvider(cacheSize), }, before: (ctx) => { ctx.state.key = (0, toHashCode_1.toHashCode)(ctx.args); const latestFailedTime = ctx.global.breakerOpenTimers.get(ctx.state.key) ?? 0; const availableTime = latestFailedTime + openDuration; if (availableTime > Date.now()) { throw new TemporaryUnAvailableError(`function [${funcName}] is temporary un-available until ${availableTime}`, ctx.global.breakerOpenReason.get(ctx.state.key)); } }, error: (ctx, error) => errorWithCircuit(error, ctx.state.key, ctx.global.breakerOpenTimers, ctx.global.breakerOpenReason), }); } exports.circuit = circuit;