← Back to Kontasks
retry.ts shared utility
Display the retry utility with exponential backoff and circuit breaker
Output
📁 shared/retry.ts
Retry utility with exponential backoff and circuit breaker pattern (241 lines)
Exports
| withRetry(fn, options) | Execute with automatic retry on failure |
| withRetryResult(fn, options) | Returns result object instead of throwing |
| CircuitBreaker | Class for preventing cascading failures |
| withCircuitBreaker(fn, breaker) | Execute with circuit breaker protection |
RetryOptions Interface
interface RetryOptions { maxRetries?: number; // default: 3 baseDelayMs?: number; // default: 1000 maxDelayMs?: number; // default: 30000 backoffMultiplier?: number; // default: 2 shouldRetry?: (error, attempt) => boolean; onRetry?: (error, attempt, delayMs) => void; }
Usage Examples
// Basic retry with defaults (3 retries, 1s base delay) const result = await withRetry(() => fetchWithTimeout(url)); // Custom retry configuration const result = await withRetry( () => fetchWithTimeout(imageUrl, { timeoutMs: 60000 }), { maxRetries: 5, baseDelayMs: 2000, onRetry: (err, attempt) => logger.warn(`Retry ${attempt}: ${err.message}`) } );
CircuitBreaker Class
const breaker = new CircuitBreaker( 5, // threshold: failures before opening 30000 // resetTimeMs: auto-reset after 30s ); // Methods: breaker.isCircuitOpen() // Check if open breaker.recordFailure() // Track failure breaker.recordSuccess() // Track success (resets failures) breaker.reset() // Manual reset breaker.getState() // { isOpen, failures, timeSinceLastFailure }
Backoff Formula
delay = min(baseDelayMs × multiplierattempt-1, maxDelayMs)
| Attempt | Delay (defaults) |
|---|---|
| 1 | 1,000ms |
| 2 | 2,000ms |
| 3 | 4,000ms |
| 4+ | capped at 30,000ms |
Quick Actions
Original Request
No layout configured
Details
Type
General
Status
Completed
Scope
vibetools
Tags
sharedutilitiescode
Created
4 Jan 2026, 11:43 am
Updated
4 Jan 2026, 11:43 am
Timing
⏱️ 59.3s
2 tools
● TTFE 6%
● Thinking 93%
● Tools 1%
Created By
claude
Raw Data
{
"id": "0154efe4-05ef-43a3-a6bd-99b0f85b4ded",
"type": "general",
"status": "completed",
"title": "retry.ts shared utility",
"description": "Display the retry utility with exponential backoff and circuit breaker",
"context": {
"output": "<div style=\"background:#1e1e1e;color:#e0e0e0;padding:20px;border-radius:8px;font-family:'Consolas','Monaco',monospace;\">\n<h2 style=\"font-family:sans-serif;color:#fff;margin:0 0 16px 0;\">📁 shared/retry.ts</h2>\n<p style=\"font-family:sans-serif;color:#9ca3af;margin:0 0 16px 0;\">Retry utility with exponential backoff and circuit breaker pattern (241 lines)</p>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#98c379;margin:0 0 12px 0;font-family:sans-serif;\">Exports</h3>\n<table style=\"width:100%;border-collapse:collapse;font-size:0.9rem;\">\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:8px 0;color:#e5c07b;\">withRetry(fn, options)</td><td style=\"color:#9ca3af;\">Execute with automatic retry on failure</td></tr>\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:8px 0;color:#e5c07b;\">withRetryResult(fn, options)</td><td style=\"color:#9ca3af;\">Returns result object instead of throwing</td></tr>\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:8px 0;color:#c678dd;\">CircuitBreaker</td><td style=\"color:#9ca3af;\">Class for preventing cascading failures</td></tr>\n<tr><td style=\"padding:8px 0;color:#e5c07b;\">withCircuitBreaker(fn, breaker)</td><td style=\"color:#9ca3af;\">Execute with circuit breaker protection</td></tr>\n</table>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#61afef;margin:0 0 12px 0;font-family:sans-serif;\">RetryOptions Interface</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#c678dd;\">interface</span> <span style=\"color:#e5c07b;\">RetryOptions</span> {\n <span style=\"color:#e06c75;\">maxRetries</span>?: <span style=\"color:#56b6c2;\">number</span>; <span style=\"color:#7f848e;\">// default: 3</span>\n <span style=\"color:#e06c75;\">baseDelayMs</span>?: <span style=\"color:#56b6c2;\">number</span>; <span style=\"color:#7f848e;\">// default: 1000</span>\n <span style=\"color:#e06c75;\">maxDelayMs</span>?: <span style=\"color:#56b6c2;\">number</span>; <span style=\"color:#7f848e;\">// default: 30000</span>\n <span style=\"color:#e06c75;\">backoffMultiplier</span>?: <span style=\"color:#56b6c2;\">number</span>; <span style=\"color:#7f848e;\">// default: 2</span>\n <span style=\"color:#e06c75;\">shouldRetry</span>?: <span style=\"color:#56b6c2;\">(error, attempt) => boolean</span>;\n <span style=\"color:#e06c75;\">onRetry</span>?: <span style=\"color:#56b6c2;\">(error, attempt, delayMs) => void</span>;\n}</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#98c379;margin:0 0 12px 0;font-family:sans-serif;\">Usage Examples</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#7f848e;\">// Basic retry with defaults (3 retries, 1s base delay)</span>\n<span style=\"color:#c678dd;\">const</span> result = <span style=\"color:#c678dd;\">await</span> <span style=\"color:#61afef;\">withRetry</span>(() => <span style=\"color:#61afef;\">fetchWithTimeout</span>(url));\n\n<span style=\"color:#7f848e;\">// Custom retry configuration</span>\n<span style=\"color:#c678dd;\">const</span> result = <span style=\"color:#c678dd;\">await</span> <span style=\"color:#61afef;\">withRetry</span>(\n () => <span style=\"color:#61afef;\">fetchWithTimeout</span>(imageUrl, { <span style=\"color:#e06c75;\">timeoutMs</span>: <span style=\"color:#d19a66;\">60000</span> }),\n {\n <span style=\"color:#e06c75;\">maxRetries</span>: <span style=\"color:#d19a66;\">5</span>,\n <span style=\"color:#e06c75;\">baseDelayMs</span>: <span style=\"color:#d19a66;\">2000</span>,\n <span style=\"color:#e06c75;\">onRetry</span>: (err, attempt) => logger.<span style=\"color:#61afef;\">warn</span>(<span style=\"color:#98c379;\">`Retry ${attempt}: ${err.message}`</span>)\n }\n);</pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;margin-bottom:16px;\">\n<h3 style=\"color:#c678dd;margin:0 0 12px 0;font-family:sans-serif;\">CircuitBreaker Class</h3>\n<pre style=\"margin:0;line-height:1.6;overflow-x:auto;\"><span style=\"color:#c678dd;\">const</span> breaker = <span style=\"color:#c678dd;\">new</span> <span style=\"color:#e5c07b;\">CircuitBreaker</span>(\n <span style=\"color:#d19a66;\">5</span>, <span style=\"color:#7f848e;\">// threshold: failures before opening</span>\n <span style=\"color:#d19a66;\">30000</span> <span style=\"color:#7f848e;\">// resetTimeMs: auto-reset after 30s</span>\n);\n\n<span style=\"color:#7f848e;\">// Methods:</span>\nbreaker.<span style=\"color:#61afef;\">isCircuitOpen</span>() <span style=\"color:#7f848e;\">// Check if open</span>\nbreaker.<span style=\"color:#61afef;\">recordFailure</span>() <span style=\"color:#7f848e;\">// Track failure</span>\nbreaker.<span style=\"color:#61afef;\">recordSuccess</span>() <span style=\"color:#7f848e;\">// Track success (resets failures)</span>\nbreaker.<span style=\"color:#61afef;\">reset</span>() <span style=\"color:#7f848e;\">// Manual reset</span>\nbreaker.<span style=\"color:#61afef;\">getState</span>() <span style=\"color:#7f848e;\">// { isOpen, failures, timeSinceLastFailure }</span></pre>\n</div>\n\n<div style=\"background:#2d2d2d;padding:16px;border-radius:6px;\">\n<h3 style=\"color:#56b6c2;margin:0 0 12px 0;font-family:sans-serif;\">Backoff Formula</h3>\n<p style=\"color:#9ca3af;margin:0;\">delay = min(baseDelayMs × multiplier<sup>attempt-1</sup>, maxDelayMs)</p>\n<table style=\"width:100%;margin-top:12px;border-collapse:collapse;font-size:0.85rem;\">\n<tr style=\"border-bottom:1px solid #444;\"><th style=\"text-align:left;padding:6px;color:#fff;\">Attempt</th><th style=\"text-align:left;padding:6px;color:#fff;\">Delay (defaults)</th></tr>\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:6px;\">1</td><td style=\"padding:6px;\">1,000ms</td></tr>\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:6px;\">2</td><td style=\"padding:6px;\">2,000ms</td></tr>\n<tr style=\"border-bottom:1px solid #444;\"><td style=\"padding:6px;\">3</td><td style=\"padding:6px;\">4,000ms</td></tr>\n<tr><td style=\"padding:6px;\">4+</td><td style=\"padding:6px;\">capped at 30,000ms</td></tr>\n</table>\n</div>\n</div>",
"requestedAt": "2026-01-04T00:00:00.000Z",
"requestId": "853d460b-5ccc-4281-8c8b-c2722416dd63",
"choices": [
{
"label": "View tests",
"value": "Show me the retry.ts tests",
"primary": true
},
{
"label": "fetch-with-timeout.ts",
"value": "Show me fetch-with-timeout.ts in shared"
},
{
"label": "All shared utilities",
"value": "List all shared utilities with descriptions"
}
],
"turnTiming": {
"totalMs": 59253,
"ttfeMs": 3630,
"thinkingMs": 54965,
"toolExecutionMs": 655,
"toolCallCount": 2,
"thinkingPct": 93,
"toolsPct": 1,
"ttfePct": 6
}
},
"createdBy": "claude",
"createdAt": "2026-01-04T01:43:31.992Z",
"updatedAt": "2026-01-04T01:43:36.294Z",
"requestId": "853d460b-5ccc-4281-8c8b-c2722416dd63",
"scope": "vibetools",
"tags": [
"shared",
"utilities",
"code"
],
"targetUser": "claude"
}