@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.
171 lines • 5.44 kB
JavaScript
/**
* @module Resilience
*/
import {} from "../../../backoff-policies/contracts/_module.js";
import { exponentialBackoff } from "../../../backoff-policies/implementations/_module.js";
import {} from "../../../execution-context/contracts/_module.js";
import {} from "../../../middleware/contracts/_module.js";
import { RetryResilienceError } from "../../../resilience/implementations/resilience.errors.js";
import {} from "../../../time-span/contracts/_module.js";
import { TimeSpan } from "../../../time-span/implementations/_module.js";
import { callInvokable, callErrorPolicyOnValue, delay, callErrorPolicyOnThrow, UnexpectedError, optionSome, optionNone, } from "../../../utilities/_module.js";
/**
* @internal
*/
export function handleOnExecutionAttempt(settings) {
const { attempt, args, context, onExecutionAttempt } = settings;
void (async () => {
try {
await callInvokable(onExecutionAttempt, {
attempt,
args,
context,
});
}
catch (error) {
console.error("Error occurred in onExecutionAttempt callback:", error);
}
})();
}
/**
* @internal
*/
export function handleOnRetryDelay(settings) {
const { onRetryDelay, error, waitTime, attempt, args, context } = settings;
void (async () => {
try {
await callInvokable(onRetryDelay, {
error,
waitTime: TimeSpan.fromTimeSpan(waitTime),
attempt,
args,
context,
});
}
catch (error_) {
console.error("Error occurred in onRetryDelay callback:", error_);
}
})();
}
/**
* @internal
*/
async function handleWhenReturn(settings) {
const { onExecutionAttempt, attempt, args, context, next, errorPolicy, maxAttempts, backoffPolicy, onRetryDelay, allErrors, } = settings;
handleOnExecutionAttempt({
onExecutionAttempt,
attempt,
args,
context,
});
const value = await next();
if (!callErrorPolicyOnValue(errorPolicy, value)) {
return optionSome(value);
}
// Handle retrying if an false is returned
allErrors.push(value);
// Only sleep if there will actually be a next attempt
if (attempt < maxAttempts) {
const waitTime = callInvokable(backoffPolicy, attempt, value);
handleOnRetryDelay({
onRetryDelay,
error: value,
waitTime,
attempt,
args,
context,
});
await delay(waitTime);
}
return optionNone();
}
/**
* @internal
*/
async function handleWhenThrow(settings) {
const { error, allErrors, attempt, maxAttempts, backoffPolicy, onRetryDelay, errorPolicy, args, context, } = settings;
if (await callErrorPolicyOnThrow(errorPolicy, error)) {
allErrors.push(error);
}
else {
throw error;
}
// Only sleep if there will actually be a next attempt
if (attempt < maxAttempts) {
const waitTime = callInvokable(backoffPolicy, attempt, error);
handleOnRetryDelay({
onRetryDelay,
error,
waitTime,
attempt,
args,
context,
});
await delay(waitTime);
}
}
/**
* @internal
*/
function throwErrors(settings) {
const { allErrors, throwLastError, maxAttempts } = settings;
if (allErrors.length !== 0 && !throwLastError) {
throw RetryResilienceError.create(allErrors, maxAttempts);
}
if (allErrors.length !== 0 && throwLastError) {
throw allErrors.at(-1);
}
throw new UnexpectedError("retry middleware reached an unreachble state, this is a bug please file issue on github.");
}
/**
* IMPORT_PATH: `@daiso-tech/core/resilience`
* @group Middlewares
* @throws {RetryResilienceError}
*/
export function retry(settings = {}) {
const { maxAttempts = 4, backoffPolicy = exponentialBackoff(), errorPolicy, onRetryDelay = () => { }, onExecutionAttempt = () => { }, throwLastError = false, } = settings;
if (maxAttempts < 1) {
throw new TypeError("RetrySettings.maxAttempts cannot be smaller than 1");
}
return async ({ args, next, context }) => {
const allErrors = [];
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const result = await handleWhenReturn({
onExecutionAttempt,
attempt,
args,
context,
next,
errorPolicy,
maxAttempts,
backoffPolicy,
onRetryDelay,
allErrors,
});
if (result.type === "some") {
return result.value;
}
}
catch (error) {
await handleWhenThrow({
error,
allErrors,
attempt,
maxAttempts,
backoffPolicy,
onRetryDelay,
errorPolicy,
args,
context,
});
}
}
return throwErrors({
allErrors,
throwLastError,
maxAttempts,
});
};
}
//# sourceMappingURL=retry.js.map