Completed
on 4 Jan 2026, 11:43 am

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
CircuitBreakerClass 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)

AttemptDelay (defaults)
11,000ms
22,000ms
34,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"
}
DashboardReportsKontasksSessionsTelemetryLogs + Go