@sailboat-computer/event-bus
Version:
Standardized event bus for sailboat computer v3 with resilience features and offline capabilities
99 lines • 3.16 kB
JavaScript
;
/**
* Retry utilities for the event bus
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.retry = exports.DEFAULT_RETRY_OPTIONS = void 0;
const logger_1 = require("./logger");
/**
* Default retry options
*/
exports.DEFAULT_RETRY_OPTIONS = {
maxRetries: 3,
baseDelay: 1000,
maxDelay: 30000,
exponential: true,
jitter: 0.2,
onRetry: (error, attempt, delay) => {
logger_1.logger.warn(`Retry attempt ${attempt} after ${delay}ms due to error: ${error.message}`);
}
};
/**
* Retry a function with exponential backoff
*
* @param fn - Function to retry
* @param options - Retry options
* @returns Promise that resolves with the function result or rejects with the last error
*/
async function retry(fn, options = {}) {
const retryOptions = {
...exports.DEFAULT_RETRY_OPTIONS,
...options
};
let lastError;
for (let attempt = 0; attempt <= retryOptions.maxRetries; attempt++) {
try {
// First attempt is not a retry
if (attempt === 0) {
return await fn();
}
// Calculate delay with exponential backoff and jitter
const delay = calculateDelay(attempt, retryOptions);
// Call onRetry callback if provided
if (retryOptions.onRetry && lastError) {
retryOptions.onRetry(lastError, attempt, delay);
}
// Wait for the calculated delay
await sleep(delay);
// Try again
return await fn();
}
catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
// Check if we've reached the maximum number of retries
if (attempt >= retryOptions.maxRetries) {
break;
}
// Check if the error is retryable
if (retryOptions.isRetryable && !retryOptions.isRetryable(lastError)) {
break;
}
}
}
// If we get here, all retries failed
if (lastError) {
throw lastError;
}
// This should never happen, but TypeScript needs it
throw new Error('Retry failed for unknown reason');
}
exports.retry = retry;
/**
* Calculate delay with exponential backoff and jitter
*
* @param attempt - Retry attempt number (1-based)
* @param options - Retry options
* @returns Delay in milliseconds
*/
function calculateDelay(attempt, options) {
// Calculate base delay
let delay = options.exponential
? Math.min(options.baseDelay * Math.pow(2, attempt - 1), options.maxDelay)
: options.baseDelay;
// Add jitter
if (options.jitter > 0) {
const jitterAmount = delay * options.jitter;
delay = delay - jitterAmount + Math.random() * jitterAmount * 2;
}
return Math.min(delay, options.maxDelay);
}
/**
* Sleep for a specified duration
*
* @param ms - Duration in milliseconds
* @returns Promise that resolves after the specified duration
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
//# sourceMappingURL=retry.js.map