(error: unknown, status?: number)
| 1473 | } |
| 1474 | |
| 1475 | function isRetryableFailure(error: unknown, status?: number): boolean { |
| 1476 | if (status === 429 || (status && status >= 500 && status <= 599)) return true |
| 1477 | if (error instanceof Error) { |
| 1478 | const code = (error as NodeJS.ErrnoException).code |
| 1479 | if (code === 'ETIMEDOUT' || code === 'ECONNRESET' || code === 'ECONNABORTED') { |
| 1480 | return true |
| 1481 | } |
| 1482 | const msg = error.message.toLowerCase() |
| 1483 | if (isBodySizeLimitError(msg)) return false |
| 1484 | return msg.includes('timeout') || msg.includes('timed out') |
| 1485 | } |
| 1486 | return false |
| 1487 | } |
| 1488 | |
| 1489 | function calculateBackoff(attempt: number, initialDelayMs: number, maxDelayMs: number): number { |
| 1490 | const base = Math.min(initialDelayMs * 2 ** attempt, maxDelayMs) |
no test coverage detected