npm package: @lasinisipsara/monicar-pulse
Description: Dependency-aware Kubernetes readiness probes backed by a central health-monitoring API
Author: lasini sipsara
Latest version: 1.0.1

# dependency-readiness

> Dependency-aware Kubernetes readiness probes backed by a central health-monitoring API.

## Install

```bash
npm install dependency-readiness axios
```

## Quick Start

```ts
import { DependencyReadiness } from 'dependency-readiness';

const readiness = new DependencyReadiness({
  healthEndpoint: 'http://health-monitor.internal/health',
  requiredDependencies: ['cache-redis', 'analytics-mysql'],
  group: 'order-service',
});

readiness.start();

// Express middleware
app.get('/readyz', readiness.middleware());

// Programmatic check
const { status } = readiness.getReadiness(); // 'READY' | 'NOT_READY'

// Graceful shutdown
process.on('SIGTERM', () => readiness.stop());
```

## Configuration

| Option | Type | Default | Description |
|---|---|---|---|
| `healthEndpoint` | `string` | **required** | URL of the central health API |
| `requiredDependencies` | `string[]` | **required** | Names of deps this service needs |
| `pollIntervalMs` | `number` | `15000` | How often to poll (ms) |
| `failureThreshold` | `number` | `2` | Consecutive DOWNs before NOT_READY |
| `maxStalenessMs` | `number` | `60000` | Ignore health data older than this |
| `timeoutMs` | `number` | `5000` | HTTP request timeout (ms) |
| `group` | `string` | `'default'` | Label included in all responses |
| `onStateChange` | `function` | — | Callback on READY ↔ NOT_READY flip |

## API

### `start()` / `stop()`
Start or stop background polling. Always call `start()` before serving traffic and `stop()` during graceful shutdown.

### `getReadiness(): ReadinessResult`
Synchronous. Returns current readiness state from internal memory — no network call.

```json
{
  "status": "READY",
  "group": "order-service",
  "timestamp": "2026-02-22T10:20:25.000Z",
  "dependencies": [
    { "name": "cache-redis", "status": "UP", "ready": true, "consecutiveFailures": 0 },
    { "name": "analytics-mysql", "status": "UP", "ready": true, "consecutiveFailures": 0 }
  ]
}
```

### `middleware()`
Returns an Express/NestJS-compatible handler. Responds `200` when READY, `503` when NOT_READY.

### Events (`EventEmitter`)
```ts
readiness.on('stateChange', (event: StateChangeEvent) => { ... });
```

```json
{
  "previousStatus": "READY",
  "currentStatus": "NOT_READY",
  "group": "order-service",
  "timestamp": "2026-02-22T10:21:00.000Z",
  "triggeredBy": "cache-redis"
}
```

## Safety Guarantees

- **No flapping**: A dependency must be reported DOWN for `failureThreshold` consecutive polls before readiness flips. A single poll returning DOWN does not affect status.
- **API failure tolerance**: Network errors and timeouts are silently swallowed. The last known good state is preserved.
- **Staleness guard**: Health data older than `maxStalenessMs` is ignored; failure counters are not incremented.
- **Unknown dependencies**: If the health API doesn't mention a required dependency, its state is left unchanged.

## Kubernetes Deployment

```yaml
readinessProbe:
  httpGet:
    path: /readyz
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3
```

Set Kubernetes `periodSeconds` ≥ `pollIntervalMs / 1000` so k8s always sees fresh data.