Retry z exponential backoff
Funkcja withRetry
Dział zatytułowany „Funkcja withRetry”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 },)Parametry
Dział zatytułowany „Parametry”interface RetryOptions { maxAttempts?: number // domyslnie 3 baseDelay?: number // domyslnie 1000 ms maxDelay?: number // domyslnie 10000 ms}| Parametr | Domyslnie | Opis |
|---|---|---|
maxAttempts | 3 | Maksymalna liczba prob (lacznie z pierwsza) |
baseDelay | 1000 ms | Bazowe opoznienie miedzy probami |
maxDelay | 10000 ms | Maksymalne opoznienie (cap) |
Wzor na opoznienie
Dział zatytułowany „Wzor na opoznienie”delay = min(baseDelay * 2^(attempt-1) + jitter, maxDelay)jitter = Math.random() * baseDelay * 0.1| Proba | Bazowe opoznienie | Z jitterem (przyklad) |
|---|---|---|
| 1 | 0 ms (natychmiast) | — |
| 2 | 1000 ms | ~1050 ms |
| 3 | 2000 ms | ~2080 ms |
| 4* | 4000 ms | ~4030 ms |
*Przy domyslnym maxAttempts: 3 czwarta proba nie nastapi.
Ktore bledy sa ponawialne
Dział zatytułowany „Ktore bledy sa ponawialne”| Blad | Ponawiany | Powod |
|---|---|---|
KsefTimeoutError | Tak | Timeout sieci — tymczasowy problem |
HTTP 429 | Tak | Rate limiting — trzeba poczekac |
HTTP 500-503 | Tak | Blad serwera — moze byc tymczasowy |
HTTP 4xx (poza 429) | Nie | Blad klienta — ponawianie nie pomoze |
TypeError (fetch) | Tak | Problem 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}Kod zrodlowy
Dział zatytułowany „Kod zrodlowy”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}Przyklady uzycia
Dział zatytułowany „Przyklady uzycia”const invoices = await withRetry(() => adapter.fetchInvoices({ from: '2026-03-01', to: '2026-03-31' }))// 3 proby, 1s bazowe opoznienieconst invoices = await withRetry( () => adapter.fetchInvoices({ from: '2026-01-01', to: '2026-03-31' }), { maxAttempts: 5, baseDelay: 2000, maxDelay: 30000 },)// 5 prob, dluzsza bazowa przerwa, wyzszy capconst result = await withRetry( () => adapter.sendInvoice({ xml: invoiceXml, nip: '5213456784' }), { maxAttempts: 2 }, // mniej prob dla operacji zapisu)