You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

109 lines
2.9 KiB

/**
* Unified backoff policy implementation
*/
import { BackoffPolicy } from './types';
import { DEFAULT_CONFIG } from './constants';
/**
* Calculate backoff delay with Retry-After + jittered exponential caps
*/
export function calculateBackoffDelay(
attempt: number,
policy: BackoffPolicy,
retryAfterMs?: number
): number {
let delay: number;
// Respect Retry-After header if present and enabled
if (policy.respectRetryAfter && retryAfterMs !== undefined) {
delay = Math.min(retryAfterMs, policy.retryAfterMaxMs || policy.maxDelayMs);
} else {
// Calculate base delay based on strategy
switch (policy.strategy) {
case 'exponential':
delay = policy.baseDelayMs * Math.pow(2, attempt - 1);
break;
case 'linear':
delay = policy.baseDelayMs * attempt;
break;
case 'fixed':
delay = policy.baseDelayMs;
break;
default:
delay = policy.baseDelayMs;
}
}
// Apply jitter if enabled
if (policy.jitterEnabled) {
const jitterRange = delay * policy.jitterFactor;
const jitter = (Math.random() - 0.5) * 2 * jitterRange;
delay = Math.max(0, delay + jitter);
}
// Cap at maximum delay
return Math.min(delay, policy.maxDelayMs);
}
/**
* Create default backoff policy
*/
export function createDefaultBackoffPolicy(): BackoffPolicy {
return {
maxAttempts: 3,
baseDelayMs: DEFAULT_CONFIG.baseDelayMs,
maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
strategy: 'exponential',
jitterEnabled: true,
jitterFactor: DEFAULT_CONFIG.jitterFactor,
respectRetryAfter: DEFAULT_CONFIG.respectRetryAfter,
retryAfterMaxMs: DEFAULT_CONFIG.retryAfterMaxMs
};
}
/**
* Create backoff policy for rate limiting
*/
export function createRateLimitBackoffPolicy(retryAfterMs: number): BackoffPolicy {
return {
maxAttempts: 5,
baseDelayMs: retryAfterMs,
maxDelayMs: Math.max(retryAfterMs * 2, DEFAULT_CONFIG.maxDelayMs),
strategy: 'fixed',
jitterEnabled: true,
jitterFactor: 0.1, // ±10% jitter for rate limits
respectRetryAfter: true,
retryAfterMaxMs: retryAfterMs * 2
};
}
/**
* Create backoff policy for network errors
*/
export function createNetworkErrorBackoffPolicy(): BackoffPolicy {
return {
maxAttempts: 3,
baseDelayMs: DEFAULT_CONFIG.baseDelayMs,
maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
strategy: 'exponential',
jitterEnabled: true,
jitterFactor: DEFAULT_CONFIG.jitterFactor,
respectRetryAfter: false
};
}
/**
* Create backoff policy for server errors (5xx)
*/
export function createServerErrorBackoffPolicy(): BackoffPolicy {
return {
maxAttempts: 3,
baseDelayMs: 2000, // Start with 2s for server errors
maxDelayMs: DEFAULT_CONFIG.maxDelayMs,
strategy: 'exponential',
jitterEnabled: true,
jitterFactor: 0.5, // ±50% jitter for server errors
respectRetryAfter: false
};
}