Przejdź do głównej zawartości

Retry z exponential backoff

import { withRetry } from '@ksefnik/core'
const invoices = await withRetry(
() => adapter.fetchInvoices({ from: '2026-03-01', to: '2026-03-31' }),
{ maxAttempts: 3, baseDelay: 1000, maxDelay: 10000 },
)
interface RetryOptions {
maxAttempts?: number // domyslnie 3
baseDelay?: number // domyslnie 1000 ms
maxDelay?: number // domyslnie 10000 ms
}
ParametrDomyslnieOpis
maxAttempts3Maksymalna liczba prob (lacznie z pierwsza)
baseDelay1000 msBazowe opoznienie miedzy probami
maxDelay10000 msMaksymalne opoznienie (cap)
delay = min(baseDelay * 2^(attempt-1) + jitter, maxDelay)
jitter = Math.random() * baseDelay * 0.1
ProbaBazowe opoznienieZ jitterem (przyklad)
10 ms (natychmiast)—
21000 ms~1050 ms
32000 ms~2080 ms
4*4000 ms~4030 ms

*Przy domyslnym maxAttempts: 3 czwarta proba nie nastapi.

BladPonawianyPowod
KsefTimeoutErrorTakTimeout sieci — tymczasowy problem
HTTP 429TakRate limiting — trzeba poczekac
HTTP 500-503TakBlad serwera — moze byc tymczasowy
HTTP 4xx (poza 429)NieBlad klienta — ponawianie nie pomoze
TypeError (fetch)TakProblem sieciowy
function isRetryable(error: unknown): boolean {
if (error instanceof KsefTimeoutError) return true
if (error instanceof KsefApiError) {
const code = error.statusCode
return code === 429 || (code !== undefined && code >= 500 && code <= 503)
}
if (error instanceof TypeError && error.message.includes('fetch')) return true
return false
}
export async function withRetry<T>(
fn: () => Promise<T>,
opts?: RetryOptions,
): Promise<T> {
const { maxAttempts, baseDelay, maxDelay } = { ...DEFAULT_OPTIONS, ...opts }
let lastError: unknown
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn()
} catch (error) {
lastError = error
if (attempt === maxAttempts || !isRetryable(error)) {
throw error
}
const exponentialDelay = baseDelay * Math.pow(2, attempt - 1)
const jitter = Math.random() * baseDelay * 0.1
const waitMs = Math.min(exponentialDelay + jitter, maxDelay)
await delay(waitMs)
}
}
throw lastError
}
const invoices = await withRetry(() =>
adapter.fetchInvoices({ from: '2026-03-01', to: '2026-03-31' })
)
// 3 proby, 1s bazowe opoznienie