UNPKG

@daiso-tech/core

Version:

The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.

104 lines 3.5 kB
/** * @module Async */ import { callInvokable, isInvokable, resolveOneOrMore, TimeSpan, } from "../../../../utilities/_module-exports.js"; import { HedgingAsyncError } from "../../../../async/async.errors.js"; import { timeoutAndFail } from "../../../../async/utilities/_module.js"; /** * The `sequentialHedging` middleware executes the primary function and all fallback functions sequentially. * It returns the result of the first successful function and automatically cancels all remaining functions. * If all function fail than error is thrown. * * IMPORT_PATH: `"@daiso-tech/core/async"` * @group Middlewares * @throws {HedgingAsyncError} {@link HedgingAsyncError} * * @example * ```ts * import { sequentialHedging } from "@daiso-tech/core/async"; * import { AsyncHooks } from "@daiso-tech/core/utilities"; * * async function fn1(signal?: AbortSignal): Promise<unknown> { * const response = await fetch("ENDPOINT-1", { signal }); * return await response.json(); * } * async function fn2(signal?: AbortSignal): Promise<unknown> { * const response = await fetch("ENDPOINT-2", { signal }); * return await response.json(); * } * async function fn3(signal?: AbortSignal): Promise<unknown> { * const response = await fetch("ENDPOINT-3", { signal }); * return await response.json(); * } * const fetchData = new AsyncHooks(fn1, [ * sequentialHedging({ * fallbacks: [ * fn2, * fn3 * ] * }) * ], { * signalBinder: { * getSignal: (args) => args[0], * forwardSignal: (args, signal) => { * args[0] = signal; * } * } * }); * * console.log(await fetchData.invoke()); * ``` */ export function sequentialHedging(settings) { const { waitTime = TimeSpan.fromSeconds(2), fallbacks, onHedgeAttempt = () => { }, onHedgeError = () => { }, } = settings; const resolvedFallbacks = resolveOneOrMore(fallbacks).map((fallback, index) => { if (isInvokable(fallback)) { return { name: `fallback-${String(index + 1)}`, func: fallback, }; } return fallback; }); return async (args, next, { context, signal, abort }) => { const errors = []; const funcs = [ { name: "__initial", func: next, }, ...resolvedFallbacks, ]; for (const { name, func } of funcs) { try { callInvokable(onHedgeAttempt, { args, context, name, }); return await timeoutAndFail((async () => callInvokable(func, ...args))(), waitTime, (error) => { abort(error); }, signal); } catch (error) { if (signal.aborted) { break; } callInvokable(onHedgeError, { args, context, error, name, }); errors.push(error); } } // If all promiseResults are rejected we will throw an error const funcNames = funcs .slice(1) .map(({ name }) => `"${name}"`) .join(", "); throw new HedgingAsyncError(`The original function and fallback functions failed: ${funcNames}`, errors); }; } //# sourceMappingURL=sequential-hedging.middleware.js.map