first commit
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# `retry-policies`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the retry-budget contract for the two automatic-recovery paths in
|
||||
the lifecycle FSM: `start_failed` (3 attempts with exponential-backoff +
|
||||
full jitter) and `crashed` (3 restarts within a rolling 60-second window
|
||||
that resets after 120 seconds of healthy operation). Backed by
|
||||
`@suaveplan/retry`'s `createExponentialBackoff` so the delay maths match
|
||||
the rest of the codebase. Throws `LIFECYCLE.RETRY_BUDGET_EXHAUSTED` when
|
||||
either budget is depleted.
|
||||
|
||||
## Features
|
||||
|
||||
- `RETRY_POLICIES` frozen registry exposing `.startFailed` and `.crashed`
|
||||
policy bundles with the configured `delay` function.
|
||||
- `START_FAILED_DEFAULTS` and `CRASHED_DEFAULTS` as named constants for
|
||||
callers that need the raw numeric defaults (e.g. admin UI tooltips).
|
||||
- `StartFailedTracker` — per-plugin attempt counter; `recordFailure()`
|
||||
throws once `maxAttempts` is reached, `markStarted()` resets.
|
||||
- `CrashBudgetTracker` — per-plugin rolling-window crash counter; honours
|
||||
`crashRestartWindowMs` to drop expired entries and `markHealthy()` for
|
||||
the cooldown reset.
|
||||
- Injectable `Clock` on `CrashBudgetTracker` so tests can drive the
|
||||
rolling window deterministically without real time.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import {
|
||||
CrashBudgetTracker,
|
||||
RETRY_POLICIES,
|
||||
StartFailedTracker,
|
||||
} from "@suaveplan/api-lifecycle/retry-policies";
|
||||
|
||||
const startTracker = new StartFailedTracker("billing");
|
||||
try {
|
||||
await plugin.start();
|
||||
startTracker.markStarted();
|
||||
} catch (err) {
|
||||
startTracker.recordFailure(); // throws once budget exhausted
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Custom policy for a host that wants 5 start attempts and a tighter crash
|
||||
window, while keeping the default delay function:
|
||||
|
||||
```ts
|
||||
import {
|
||||
type CrashedPolicy,
|
||||
type StartFailedPolicy,
|
||||
RETRY_POLICIES,
|
||||
} from "@suaveplan/api-lifecycle/retry-policies";
|
||||
|
||||
const startPolicy: StartFailedPolicy = {
|
||||
...RETRY_POLICIES.startFailed,
|
||||
maxAttempts: 5,
|
||||
};
|
||||
const crashPolicy: CrashedPolicy = {
|
||||
...RETRY_POLICIES.crashed,
|
||||
crashRestartMax: 5,
|
||||
crashRestartWindowMs: 30_000,
|
||||
};
|
||||
```
|
||||
|
||||
Deterministic testing — feed the tracker a fake clock to step through the
|
||||
rolling window in zero wall-clock time:
|
||||
|
||||
```ts
|
||||
import { CrashBudgetTracker, RETRY_POLICIES } from "@suaveplan/api-lifecycle/retry-policies";
|
||||
|
||||
let now = 0;
|
||||
const tracker = new CrashBudgetTracker("billing", RETRY_POLICIES.crashed, () => now);
|
||||
tracker.recordCrash();
|
||||
now += RETRY_POLICIES.crashed.crashRestartWindowMs + 1;
|
||||
tracker.recordCrash(); // old crash dropped — counts as first
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `RETRY_POLICIES` — frozen `{ startFailed, crashed }`.
|
||||
- `START_FAILED_DEFAULTS`, `CRASHED_DEFAULTS` — raw constants.
|
||||
- `class StartFailedTracker` — `recordFailure`, `markStarted`, `count`.
|
||||
- `class CrashBudgetTracker` — `recordCrash`, `markHealthy`, `count`.
|
||||
- `type StartFailedPolicy`, `type CrashedPolicy`, `type Clock`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The crash tracker stores timestamps in an array — when the window grows
|
||||
past 3 a `LIFECYCLE.RETRY_BUDGET_EXHAUSTED` throw fires. The filter-on-each
|
||||
-record approach is fine for the small numbers involved (max 3 + one
|
||||
overflow); a ring buffer is overkill here. The trackers are deliberately
|
||||
not coupled to the FSM factory — the host driver wires them together so a
|
||||
custom driver can substitute its own budget policy without changing the
|
||||
state-machine wiring.
|
||||
Reference in New Issue
Block a user