self-serve-integration-service
Version:
Self-Serve Integration Service for managing multiple funder integrations including REST APIs, SOAP APIs, and UI automation
127 lines (114 loc) • 3.94 kB
text/typescript
/**
* Retry Configuration Utility
*
* Provides dynamic retry configuration from environment variables
* with fallback to default values and support for funder-specific overrides.
*/
export interface RetryConfig {
enabled: boolean;
maxRetries: number;
baseDelay: number;
maxDelay: number;
backoffMultiplier: number;
}
/**
* Get global retry configuration from environment variables
*/
export function getGlobalRetryConfig(): RetryConfig {
return {
enabled: process.env['API_RETRY_ENABLED'] !== 'false',
maxRetries: parseInt(process.env['API_MAX_RETRIES'] || '3', 10),
baseDelay: parseInt(process.env['API_RETRY_BASE_DELAY'] || '1000', 10),
maxDelay: parseInt(process.env['API_RETRY_MAX_DELAY'] || '10000', 10),
backoffMultiplier: parseFloat(process.env['API_RETRY_BACKOFF_MULTIPLIER'] || '2'),
};
}
/**
* Get funder-specific retry configuration with fallback to global config
*
* @param funderName - Name of the funder (e.g., "LEX", "ALPHABET")
* @returns RetryConfig with funder-specific overrides applied
*
* @example
* // Get LEX-specific retry config (uses LEX_MAX_RETRIES if set, otherwise API_MAX_RETRIES)
* const lexConfig = getFunderRetryConfig('LEX');
*
* // Get Alphabet-specific retry config
* const alphabetConfig = getFunderRetryConfig('ALPHABET');
*/
export function getFunderRetryConfig(funderName: string): RetryConfig {
const globalConfig = getGlobalRetryConfig();
const funderPrefix = funderName.toUpperCase();
return {
enabled: globalConfig.enabled,
maxRetries: parseInt(
process.env[`${funderPrefix}_MAX_RETRIES`] || process.env['API_MAX_RETRIES'] || '3',
10
),
baseDelay: parseInt(
process.env[`${funderPrefix}_RETRY_BASE_DELAY`] ||
process.env['API_RETRY_BASE_DELAY'] ||
'1000',
10
),
maxDelay: parseInt(
process.env[`${funderPrefix}_RETRY_MAX_DELAY`] ||
process.env['API_RETRY_MAX_DELAY'] ||
'10000',
10
),
backoffMultiplier: parseFloat(process.env['API_RETRY_BACKOFF_MULTIPLIER'] || '2'),
};
}
/**
* Calculate retry delay using exponential backoff
*
* @param attempt - Current attempt number (1-based)
* @param config - Retry configuration
* @returns Delay in milliseconds
*
* @example
* // Calculate delay for 3rd attempt with default config
* const delay = calculateRetryDelay(3, getGlobalRetryConfig());
* // Returns: min(1000 * 2^2, 10000) = 4000ms
*/
export function calculateRetryDelay(attempt: number, config: RetryConfig): number {
const exponentialDelay = config.baseDelay * Math.pow(config.backoffMultiplier, attempt - 1);
return Math.min(exponentialDelay, config.maxDelay);
}
/**
* Check if retry should be attempted based on configuration and attempt count
*
* @param attempt - Current attempt number (1-based)
* @param config - Retry configuration
* @returns true if retry should be attempted
*/
export function shouldRetry(attempt: number, config: RetryConfig): boolean {
return config.enabled && attempt < config.maxRetries;
}
/**
* Validate retry configuration
* Throws error if configuration is invalid
*/
export function validateRetryConfig(config: RetryConfig): void {
if (config.maxRetries < 0) {
throw new Error('maxRetries must be >= 0');
}
if (config.baseDelay < 0) {
throw new Error('baseDelay must be >= 0');
}
if (config.maxDelay < config.baseDelay) {
throw new Error('maxDelay must be >= baseDelay');
}
if (config.backoffMultiplier < 1) {
throw new Error('backoffMultiplier must be >= 1');
}
}
/**
* Format retry configuration for logging
*/
export function formatRetryConfig(config: RetryConfig): string {
return `enabled=${config.enabled}, maxRetries=${config.maxRetries}, baseDelay=${config.baseDelay}ms, maxDelay=${config.maxDelay}ms, multiplier=${config.backoffMultiplier}`;
}
// Export default global config
export default getGlobalRetryConfig();