# @suaveplan/retry - Retry strategies with exponential/linear/constant backoff, jitter, circuit breaker with half-open probing, sleep and timeout helpers ## Summary Retry strategies and circuit-breaker for async operations. The package provides constant, linear, and exponential backoff with four jitter modes (full, equal, decorrelated, none), a `sleep` helper with AbortSignal support, a per-attempt `withTimeout` wrapper, and a three-state circuit breaker (closed → open → half-open) with event emission and configurable failure/success thresholds. All entry points accept an injectable `Clock` and `AbortSignal` so they integrate cleanly with test harnesses and request cancellation. ## Documentation tree - [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_ - [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_ - [errors](./src/errors/retry-error.md) — _(no submodules)_ - [retry-error](./src/errors/retry-error.md) — _(no submodules)_ - [otel](./src/otel/retry-otel.md) — _(no submodules)_ - [retry-otel](./src/otel/retry-otel.md) — _(no submodules)_ - [retry](./src/retry/retry.md) — _(no submodules)_ - [retry](./src/retry/retry.md) — _(no submodules)_ - [constant](./src/strategies/constant/constant.md) — _(no submodules)_ - [constant](./src/strategies/constant/constant.md) — _(no submodules)_ - [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_ - [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_ - [linear](./src/strategies/linear/linear.md) — _(no submodules)_ - [linear](./src/strategies/linear/linear.md) — _(no submodules)_ - [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_- [errors](./src/errors/retry-error.md) — _(no submodules)_- [retry-error](./src/errors/retry-error.md) — _(no submodules)_- [otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry-otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_- [errors](./src/errors/retry-error.md) — _(no submodules)_- [retry-error](./src/errors/retry-error.md) — _(no submodules)_- [otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry-otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_- [errors](./src/errors/retry-error.md) — _(no submodules)_- [retry-error](./src/errors/retry-error.md) — _(no submodules)_- [otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry-otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_- [circuit-breaker](./src/circuit-breaker/circuit-breaker.md) — _(no submodules)_- [errors](./src/errors/retry-error.md) — _(no submodules)_ - [retry-error](./src/errors/retry-error.md) — _(no submodules)_- [otel](./src/otel/retry-otel.md) — _(no submodules)_ - [retry-otel](./src/otel/retry-otel.md) — _(no submodules)_- [retry](./src/retry/retry.md) — _(no submodules)_ - [retry](./src/retry/retry.md) — _(no submodules)_- [constant](./src/strategies/constant/constant.md) — _(no submodules)_ - [constant](./src/strategies/constant/constant.md) — _(no submodules)_- [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_ - [exponential](./src/strategies/exponential/exponential.md) — _(no submodules)_- [linear](./src/strategies/linear/linear.md) — _(no submodules)_ - [linear](./src/strategies/linear/linear.md) — _(no submodules)_ ## Install ```sh bun add @suaveplan/retry ``` ## Quick Start ```ts import { withRetry, createExponentialBackoff, CircuitBreaker, } from "@suaveplan/retry"; // Retry with exponential backoff and full jitter — up to 5 attempts. const result = await withRetry( async (signal) => { const res = await fetch("https://api.example.com/data", { signal }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); }, { maxAttempts: 5, delay: createExponentialBackoff({ initial: 100, max: 5000, jitter: "full" }), } ); // Wrap a sensitive downstream call in a circuit breaker. const breaker = new CircuitBreaker({ failureThreshold: 3, successThreshold: 2, timeout: 10_000, }); breaker.on("open", ({ openedAt }) => console.warn("Circuit opened at", openedAt)); const value = await breaker.call(async (signal) => { return fetchDownstream(signal); }); ``` ## Modules | Module | Path | |--------|------| | `retry` — core loop, `retry`, `withRetry`, `sleep`, `withTimeout`, `createDelayFn` | [`src/retry/retry.md`](src/retry/retry.md) | | `constant` — `createConstantBackoff` | [`src/strategies/constant/constant.md`](src/strategies/constant/constant.md) | | `linear` — `createLinearBackoff` | [`src/strategies/linear/linear.md`](src/strategies/linear/linear.md) | | `exponential` — `createExponentialBackoff`, `applyJitter` | [`src/strategies/exponential/exponential.md`](src/strategies/exponential/exponential.md) | | `circuit-breaker` — `CircuitBreaker` class, `CircuitBreakerConfig`, event map | [`src/circuit-breaker/circuit-breaker.md`](src/circuit-breaker/circuit-breaker.md) | | `retry-error` — `RetryExhaustedError`, `RetryAbortedError`, `AttemptTimeoutError`, `CircuitOpenError` | [`src/errors/retry-error.md`](src/errors/retry-error.md) | | `retry-otel` — OpenTelemetry span/event helpers | [`src/otel/retry-otel.md`](src/otel/retry-otel.md) |