Skip to main content
Glama
retry.ts2.51 kB
import { getConfig } from './config.js'; import { logger } from './logger.js'; const TRANSIENT_PATTERNS = new Set([ 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED', 'socket hang up', 'network', 'timeout', 'too many requests', '429', '503', '504', 'RequestTimeout', 'ServiceUnavailable', 'ThrottlingException' ]); export function isTransientError(error: string | Error): boolean { const msg = (typeof error === 'string' ? error : error.message).toLowerCase(); for (const pattern of TRANSIENT_PATTERNS) { if (msg.includes(pattern.toLowerCase())) return true; } return false; } const sleep = (ms: number): Promise<void> => new Promise(r => setTimeout(r, ms)); export function calculateBackoff(attempt: number, baseDelay: number): number { const exp = baseDelay * Math.pow(2, attempt); const jitter = exp * 0.25 * (Math.random() * 2 - 1); return Math.min(exp + jitter, 30000); } export interface RetryOptions { maxRetries?: number; baseDelay?: number; isRetryable?: (error: Error) => boolean; onRetry?: (error: Error, attempt: number, delay: number) => void; } export async function withRetry<T>( operation: () => Promise<T>, name: string, options: RetryOptions = {} ): Promise<T> { const config = getConfig(); const maxRetries = options.maxRetries ?? config.maxRetries; const baseDelay = options.baseDelay ?? config.retryDelayMs; const isRetryable = options.isRetryable ?? (e => isTransientError(e)); let lastError: Error = new Error(`${name} failed without specific error`); for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await operation(); } catch (err) { lastError = err instanceof Error ? err : new Error(String(err)); if (attempt < maxRetries && isRetryable(lastError)) { const delay = calculateBackoff(attempt, baseDelay); logger.warn(`Retrying ${name}`, { attempt: attempt + 1, maxRetries, delayMs: Math.round(delay) }); options.onRetry?.(lastError, attempt + 1, delay); await sleep(delay); } else { break; } } } logger.error(`${name} failed after ${maxRetries + 1} attempts`, lastError!); throw lastError!; } export const createRetryWrapper = (defaults: RetryOptions = {}) => <T>(op: () => Promise<T>, name: string, opts?: RetryOptions) => withRetry(op, name, { ...defaults, ...opts });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vedantparmar12/Azure-_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server