trainingpeaks-sdk
Version:
TypeScript SDK for TrainingPeaks API integration
87 lines (86 loc) • 3.4 kB
JavaScript
import { isRetryableError } from '../../adapters/errors/http-errors.js';
export class RetryHandler {
constructor(config) {
this.config = config;
this.config = {
maxDelay: 30000,
jitter: true,
...config,
};
}
async execute(operation, context) {
let lastError;
for (let attempt = 1; attempt <= this.config.attempts; attempt++) {
try {
if (attempt > 1 && context?.logger) {
context.logger.warn('Retrying HTTP request', {
requestId: context.requestId,
attempt,
totalAttempts: this.config.attempts,
url: context.url,
method: context.method,
});
}
return await operation();
}
catch (error) {
lastError = error;
if (attempt === this.config.attempts || !isRetryableError(error)) {
if (context?.logger) {
context.logger.error('HTTP request failed after retries', {
requestId: context.requestId,
finalAttempt: attempt,
totalAttempts: this.config.attempts,
url: context.url,
method: context.method,
error: error instanceof Error ? error.message : String(error),
errorCode: error && typeof error === 'object' && 'code' in error
? error.code
: undefined,
retryable: isRetryableError(error),
});
}
throw error;
}
const delay = this.calculateDelay(attempt);
if (context?.logger) {
context.logger.info('HTTP request failed, will retry', {
requestId: context.requestId,
attempt,
totalAttempts: this.config.attempts,
nextRetryIn: `${Math.round(delay)}ms`,
url: context.url,
method: context.method,
error: error instanceof Error ? error.message : String(error),
errorCode: error && typeof error === 'object' && 'code' in error
? error.code
: undefined,
});
}
await this.delay(attempt);
}
}
throw lastError;
}
calculateDelay(attempt) {
let delay = this.config.delay * Math.pow(this.config.backoff, attempt - 1);
if (this.config.maxDelay) {
delay = Math.min(delay, this.config.maxDelay);
}
if (this.config.jitter) {
delay = delay * (0.5 + Math.random() * 0.5);
}
return delay;
}
async delay(attempt) {
const delay = this.calculateDelay(attempt);
return new Promise((resolve) => setTimeout(resolve, Math.round(delay)));
}
}
export const DEFAULT_RETRY_CONFIG = {
attempts: 3,
delay: 1000,
backoff: 2,
maxDelay: 10000,
jitter: true,
};