@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.
79 lines • 2.98 kB
JavaScript
/**
* @module Async
*/
import { callInvokable, TimeSpan, } from "../../../utilities/_module-exports.js";
import { exponentialBackoffPolicy, } from "../../../async/backof-policies/_module.js";
import { AbortAsyncError, RetryAsyncError } from "../../../async/async.errors.js";
import { LazyPromise } from "../../../async/utilities/_module.js";
/**
* The `retry` middleware enables automatic retries for all errors or specific errors, with configurable backoff policies.
* An error will be thrown when all retry attempts fail.
*
* IMPORT_PATH: `"@daiso-tech/core/async"`
* @group Middleware
*
* @throws {AbortAsyncError} {@link AbortAsyncError}
*
* @example
* ```ts
* import { retry } from "@daiso-tech/core/async";
* import { AsyncHooks } from "@daiso-tech/core/utilities";
*
* await new AsyncHooks(async (url: string) => {
* const response = await fetch(url);
* const json = await response.json();
* if (!response.ok) {
* throw json
* }
* return json;
* }, retry({ maxAttempts: 8 })).invoke("URL_ENDPOINT");
* ```
*/
export function retry(settings = {}) {
const { maxAttempts = 4, backoffPolicy = exponentialBackoffPolicy(), retryPolicy = () => true, onRetryStart = () => { }, onRetryEnd = () => { }, onExecutionAttempt = () => { }, } = settings;
return async (args, next, context) => {
const errors = [];
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
callInvokable(onExecutionAttempt, { attempt, args, context });
return await next(...args);
}
catch (error) {
const time = TimeSpan.fromMilliseconds(callInvokable(backoffPolicy, attempt, error));
callInvokable(onRetryStart, {
error,
waitTime: time,
attempt,
args,
context,
});
errors.push(error);
if (error instanceof AbortAsyncError) {
throw error;
}
if (!callInvokable(retryPolicy, error, attempt)) {
throw error;
}
await LazyPromise.delay(time);
callInvokable(onRetryEnd, {
error,
waitTime: time,
attempt,
args,
context,
});
}
}
let errorMessage = `Promise was failed after retried ${String(maxAttempts)} times`;
const lastError = errors[errors.length - 1];
if (lastError) {
// eslint-disable-next-line @typescript-eslint/no-base-to-string
errorMessage = `${errorMessage} and last thrown error was "${String(lastError)}"`;
}
throw new RetryAsyncError(errorMessage, {
errors,
maxAttempts,
});
};
}
//# sourceMappingURL=retry.middleware.js.map