/** * Stop hammering a server that is not answering. * * ── The behaviour this replaces ─────────────────────────────────────────── * Every walk tried every configured target, in full, forever. A target that was * down did not merely fail — it failed SLOWLY, once per session, inside the same * serial walk as the healthy one: connect timeout, three retries with 2s/8s/30s * backoff, then the next session. One measured log carried 1,772 `fetch failed` * and 3,526 HTTP 429 and was still producing them at 26–38 per hour, days later. * * The cost lands on the wrong target. Because targets are walked in sequence, a * dead LAN box delays every ship to the healthy SaaS host behind it, and the * whole walk's completion — which is what the ledger, the health file and the * progress report all wait on. * * ── The rule ───────────────────────────────────────────────────────────── * Consecutive whole-walk failures trip the breaker. It stays open for a * doubling cooldown, capped, and one success closes it completely. * * Deliberately counted per WALK, not per request. A single walk already retries * internally and obeys Retry-After; failing individual requests are normal * operation and must not trip anything. What "the target is down" actually looks * like is a whole walk failing, repeatedly. * * Process-lifetime only, and that is the right lifetime: a restart is exactly * when you want to retry a target you gave up on. Nothing is persisted. * * A tripped breaker is never silent. It is reported to the health file so the * user hears "this server is being skipped" instead of watching a target quietly * never sync. */ /** Consecutive failed walks before a target is skipped. */ export declare const TRIP_AFTER_FAILURES: number; /** First cooldown, doubled per subsequent failure. */ export declare const BASE_COOLDOWN_MS: number; /** Ceiling, so a target is always retried eventually. */ export declare const MAX_COOLDOWN_MS: number; /** Test seam. */ export declare function _resetBreakers(): void; /** Cooldown for the Nth consecutive failure, doubling and capped. */ export declare function cooldownFor(failures: number): number; export interface BreakerVerdict { /** True when this target should be skipped right now. */ open: boolean; /** Milliseconds until the next attempt. 0 when closed. */ retryInMs: number; failures: number; lastError: string; /** * True only for the failure that OPENS a new incident. * * A tripped breaker re-opens on every attempt until a success clears it, so a * caller that reports "tripped" on each open verdict counts elapsed time, not * incidents. One device reported 823 trips for ONE LAN box that was switched * off — 96 a day, for as long as the box stayed off — and the fleet panel read * that back as if 823 separate things had gone wrong. * * `failures` is the number to read for "how bad is it"; this flag is the one * to count. */ tripped: boolean; } /** Should this target be skipped? */ export declare function breakerState(serverUrl: string, now?: number): BreakerVerdict; /** A walk against this target completed. Clear everything. */ export declare function noteTargetSuccess(serverUrl: string): void; /** * A walk against this target failed. Returns the verdict for the NEXT attempt, * so the caller can report "skipping for 4m" in the same breath as the failure. */ export declare function noteTargetFailure(serverUrl: string, error: string, now?: number): BreakerVerdict; /** One line for the log, or null when there is nothing to say. */ export declare function breakerNotice(serverUrl: string, v: BreakerVerdict): string | null; //# sourceMappingURL=target-breaker.d.ts.map