SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%
1.3 KB · 36 lines typescript
Raw Blame History
1import { PolyProviderError } from "./types";2import { sleep } from "@/lib/utils";34export interface RetryOptions {5  maxAttempts?: number;6  baseDelayMs?: number;7  maxDelayMs?: number;8  signal?: AbortSignal;9  onRetry?: (attempt: number, error: PolyProviderError, delayMs: number) => void;10}1112/**13 * Exponential backoff with full jitter. Only retries errors flagged `retryable`14 * (429 / 5xx / network / timeout). Auth, invalid request and unsupported-parameter15 * errors are never retried. Respects Retry-After when present.16 */17export async function withRetry<T>(fn: (attempt: number) => Promise<T>, normalize: (e: unknown) => PolyProviderError, opts: RetryOptions = {}): Promise<T> {18  const max = opts.maxAttempts ?? 3;19  const base = opts.baseDelayMs ?? 500;20  const cap = opts.maxDelayMs ?? 8_000;21  let attempt = 0;22  while (true) {23    attempt++;24    try {25      return await fn(attempt);26    } catch (raw) {27      const err = normalize(raw);28      if (!err.retryable || attempt >= max || opts.signal?.aborted || err.code === "CANCELLED") throw err;29      const backoff = Math.min(cap, base * 2 ** (attempt - 1));30      const delay = err.retryAfterMs ?? Math.round(Math.random() * backoff);31      opts.onRetry?.(attempt, err, delay);32      await sleep(delay, opts.signal);33    }34  }35}36