MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / withRetry

Function withRetry

src/utils/retry.ts:122–167  ·  view source on GitHub ↗
(fn: (attempt: number) => Promise<T>, opts: RetryOptions = {})

Source from the content-addressed store, hash-verified

120 * permanent). The first attempt has attempt index 0.
121 */
122export async function withRetry<T>(fn: (attempt: number) => Promise<T>, opts: RetryOptions = {}): Promise<T> {
123 const maxAttempts = opts.maxAttempts ?? 4;
124 const baseMs = opts.baseMs ?? 400;
125 const capMs = opts.capMs ?? 8000;
126 const retryable = opts.isRetryable ?? isTransientError;
127 const maxRetryAfterMs = opts.maxRetryAfterMs ?? 60_000;
128 const label = opts.label ?? 'op';
129
130 let lastErr: unknown;
131 for (let attempt = 0; attempt < maxAttempts; attempt++) {
132 if (opts.signal?.aborted) throw new Error('aborted');
133 try {
134 return await fn(attempt);
135 } catch (err) {
136 lastErr = err;
137 const isLast = attempt === maxAttempts - 1;
138 if (isLast || !retryable(err)) throw err;
139
140 // Compute wait: prefer server's Retry-After, else full-jitter backoff.
141 const server = retryAfterMs(err);
142 // A Retry-After longer than we're willing to block (e.g. a daily quota
143 // 429 asking for many minutes) → fail fast instead of hanging the turn.
144 if (server !== undefined && server > maxRetryAfterMs) {
145 logger.warn(`Retry ${label}: server Retry-After ${Math.round(server / 1000)}s exceeds cap ${Math.round(maxRetryAfterMs / 1000)}s — giving up (switch model/provider)`, {
146 status: statusOf(err),
147 });
148 throw err;
149 }
150 const expo = Math.min(capMs, baseMs * 2 ** attempt);
151 const wait = server ?? Math.floor(Math.random() * expo);
152 logger.warn(`Retry ${label}`, {
153 attempt: attempt + 1,
154 maxAttempts,
155 waitMs: wait,
156 status: statusOf(err),
157 err: String((err as any)?.message ?? err).slice(0, 160),
158 });
159 try {
160 await abortableSleep(wait, opts.signal);
161 } catch {
162 throw err; // aborted during backoff → surface the original error
163 }
164 }
165 }
166 throw lastErr;
167}

Callers 4

completeMethod · 0.85
completeMethod · 0.85
completeMethod · 0.85

Calls 4

retryAfterMsFunction · 0.85
statusOfFunction · 0.85
abortableSleepFunction · 0.85
warnMethod · 0.80

Tested by

no test coverage detected