first commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# `health-checker/health-checker`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
`HealthChecker` is the orchestration core of `@suaveplan/health-check`. It owns a registry of dependency checks, runs them on demand, enforces per-check timeouts through an injected `TimersLike`, caches results for a configurable TTL, and produces standardised health, readiness, and liveness payloads suitable for the `/health`, `/ready`, and `/live` endpoints common to Kubernetes, ECS, Nomad, and reverse-proxy probes. Wall-clock readings come from the injected `Clock`, so tests can drive deterministic uptime + cache-expiry behaviour.
|
||||
|
||||
## Features
|
||||
|
||||
- Registry of `DependencyCheckConfig` with per-check `critical`, `timeout`, and `cacheTtlMs` overrides.
|
||||
- Result aggregation that returns `healthy` / `degraded` / `unhealthy`: critical failures short-circuit, non-critical or degraded results downgrade to `degraded`.
|
||||
- Typed `EventBus<HealthEventMap>` emitting `check:passed`, `check:failed`, and `status:changed` events.
|
||||
- Zod-validated boundaries — every option object is parsed before use; failures throw `HealthCheckError` with `INVALID_OPTIONS`.
|
||||
- OTel instrumentation: every check run records on `health_check_runs_total` + `health_check_duration_ms`, and every aggregate evaluation increments `health_check_aggregate_status_total`.
|
||||
- Optional `LoggerLike` injection for `debug` registration logs and `warn` on failed checks.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { HealthChecker, createHttpCheck } from "@suaveplan/health-check";
|
||||
|
||||
const checker = new HealthChecker({ name: "api", version: "1.0.0" });
|
||||
checker.addCheck({
|
||||
name: "upstream",
|
||||
check: createHttpCheck({ url: "https://up.example.com/health" }),
|
||||
});
|
||||
const response = await checker.health();
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { HealthChecker, HealthEvent } from "@suaveplan/health-check";
|
||||
|
||||
const checker = new HealthChecker({
|
||||
name: "api",
|
||||
defaultTimeout: 2_000,
|
||||
defaultCacheTtlMs: 5_000,
|
||||
clock: () => performance.now() + epoch,
|
||||
timers: fakeTimers,
|
||||
logger,
|
||||
});
|
||||
|
||||
checker.events.on(HealthEvent.STATUS_CHANGED, ({ previous, current }) => {
|
||||
pagerduty.notify({ previous, current });
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new HealthChecker(options)` — `options.name` required; `version`, `defaultTimeout`, `defaultCacheTtlMs`, `checks`, `clock`, `timers`, `logger` optional.
|
||||
- `addCheck(config)` / `removeCheck(name)` / `getCheckNames()`.
|
||||
- `runCheck(name)` → `CheckResult` (single check, honours cache).
|
||||
- `health()` → `HealthResponse` (runs all, aggregates).
|
||||
- `ready()` → `ReadinessResponse` (critical-only failures).
|
||||
- `live()` → `LivenessResponse` (process is responding).
|
||||
- `clearCache()` / `getUptimeMs()`.
|
||||
- `events: EventBus<HealthEventMap>`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Timeout enforcement is delegated to the injected `TimersLike` rather than `setTimeout` so tests can drive timeouts deterministically without `vi.useFakeTimers()`. The cache is keyed by check name and stores a frozen `CheckResult` with an absolute `expiresAt` computed against `this.clock()` — clock skew between writes and reads cannot leak negative TTLs because we re-read the clock on every check. Cached reads tag results with `cached: true` so consumers can distinguish them. Failures inside `executeWithTimeout` are wrapped in `HealthCheckError(CHECK_EXECUTION_FAILED)` so the outer `runCheck` always sees a typed error; the `CHECK_TIMEOUT` branch is preserved separately so it can be surfaced in `details.timedOut`.
|
||||
Reference in New Issue
Block a user