@boolean-packages/boolean-healthcheck-sdk
v0.1.0
Published
Framework-agnostic health-check SDK to expose /health (liveness + readiness) from Node apps
Readme
@boolean-packages/boolean-healthcheck-sdk (TypeScript) — Endpoint /health agnóstico
SDK de lado servidor para que cualquier app Node (NestJS, Express, Fastify, server HTTP plano) exponga un endpoint /health robusto que combine liveness ("estoy vivo": proceso responde, disco/RAM ok) y readiness ("puedo trabajar": DB, Redis, RabbitMQ, APIs de terceros).
Es agnóstico del framework: provee el motor de checks (HealthRegistry) y un handler puro (createHealthHandler) que montás donde quieras.
Orquestador (k8s, load balancer, uptime monitor) ──▶ GET /health ──▶ HealthRegistry ──▶ [DB, Redis, RabbitMQ, HTTP, disco, RAM]Instalación
npm install @boolean-packages/boolean-healthcheck-sdk
# Drivers opcionales — sólo los que tu app use (peerDependencies):
npm install pg # postgresCheck({ connectionString })
npm install ioredis # redisCheck({ url })
npm install amqplib # rabbitmqCheck({ url })Importar el paquete nunca importa los drivers opcionales: se cargan con
import()dinámico sólo cuando un check usaconnectionString/url. Si el driver no está instalado, se lanzaMissingDriverErrorcon el comando de instalación. Si pasás un cliente/pool ya creado, el driver ni se importa.
Build, tests y typecheck
cd sdks/healthcheck-typescript
npm install
npm run typecheck
npm test
npm run build # genera ESM + CJS + .d.ts en dist/Concepto
HealthRegistry— registra checks y los corre en paralelo con timeout (Promise.race, responde rápido y nunca cuelga). Cache TTL opcional para no golpear las dependencias en cada poll.HealthCheck—{ name, critical?, run() }.run()devuelve un detalle o lanza/rechaza. Un checkcriticalcaído → 503 DOWN; uno no-crítico caído → 200 DEGRADED.createHealthHandler— devuelve(req?) => Promise<{ httpStatus, body }>. Público devuelve{ status: "UP" }; el detalle por dependencia sólo se expone con API key / IP autorizada.
Uso básico
import {
HealthRegistry,
createHealthHandler,
postgresCheck,
redisCheck,
rabbitmqCheck,
httpCheck,
diskSpaceCheck,
} from "@boolean-packages/boolean-healthcheck-sdk";
const registry = new HealthRegistry({ timeoutMs: 2000, cacheTtlMs: 5000, version: "1.4.0" })
.register(diskSpaceCheck({ path: "/", minFreeRatio: 0.1 })) // liveness
.register(postgresCheck({ pool })) // SELECT 1
.register(redisCheck({ client: redis, critical: false })) // degrada, no tumba
.register(rabbitmqCheck({ connection: amqp }))
.register(httpCheck({ url: "https://pagos.proveedor.com/ping" })); // tercero crítico
const handler = createHealthHandler(registry, { detailApiKey: "super-secreto" });Los checks reciben clientes/pools/conexiones ya existentes (no gestionan el pool). Como conveniencia también aceptan connectionString/url para una conexión efímera.
Montaje por framework (ejemplos, sin acoplamiento)
Express
app.get("/health", async (req, res) => {
const { httpStatus, body } = await handler({ headers: req.headers, ip: req.ip });
res.status(httpStatus).json(body);
});NestJS (controller)
@Controller("health")
export class HealthController {
@Get()
async health(@Req() req: Request, @Res() res: Response) {
const { httpStatus, body } = await handler({ headers: req.headers, ip: req.ip });
res.status(httpStatus).json(body);
}
}Server HTTP plano
import { createServer } from "node:http";
createServer(async (req, res) => {
if (req.url === "/health") {
const { httpStatus, body } = await handler({
headers: req.headers as Record<string, string>,
ip: req.socket.remoteAddress,
});
res.writeHead(httpStatus, { "content-type": "application/json" });
res.end(JSON.stringify(body));
}
}).listen(3000);Códigos de estado
| Situación | status | HTTP |
|-----------------------------------------------|------------|------|
| Todos los checks OK | UP | 200 |
| Sólo checks no-críticos caídos | DEGRADED | 200 |
| Al menos un check crítico caído / timeout | DOWN | 503 |
Respuesta
Pública (sin autorización):
{ "status": "UP" }Detallada (con x-health-key válida o IP en allowedIps):
{
"status": "DEGRADED",
"checks": [
{ "name": "postgres", "status": "UP", "latencyMs": 1.4, "critical": true },
{ "name": "redis", "status": "DEGRADED", "latencyMs": 2000, "critical": false,
"detail": "Health check 'redis' timed out after 2000ms" }
],
"version": "1.4.0",
"uptimeSeconds": 3601.2
}Seguridad del detalle
const handler = createHealthHandler(registry, {
detailApiKey: "super-secreto", // comparación en tiempo constante
detailHeader: "x-health-key", // default
allowedIps: ["10.0.0.0", "127.0.0.1"],
});Sin API key correcta ni IP autorizada, el handler devuelve sólo { status: ... } — no revela qué dependencia falló.
Checks built-in
| Check | Driver (peer) | Probe |
|-------------------|--------------------|-----------------------------------------|
| diskSpaceCheck | — (fs.statfs) | espacio libre vs umbral |
| memoryCheck | — (os) | % memoria usada vs umbral |
| postgresCheck | pg (sólo con connectionString) | SELECT 1 |
| redisCheck | ioredis (sólo con url) | PING |
| rabbitmqCheck | amqplib (sólo con url) | abre y cierra un channel |
| httpCheck | — (fetch nativo, Node 18+) | GET a URL, status 2xx |
Check propio: pasá cualquier objeto { name, critical?, run() } a registry.register(...), o usá registry.add("nombre", async () => {...}, { critical }).
Manejo de errores
Todas las excepciones del SDK extienden HealthSDKError:
| Error | Contexto |
|----------------------|-----------------------------------------------------------|
| MissingDriverError | usás un check cuyo driver opcional no está instalado |
| CheckTimeoutError | mensaje usado al reportar un check que excedió el timeout |
Las fallas de las dependencias no se propagan: se reflejan en status/httpStatus del reporte.
Exports del paquete
@boolean-packages/boolean-healthcheck-sdk → HealthRegistry, createHealthHandler, checks built-in, tipos, erroresNotas de despliegue
- Usa
fetchnativo (Node 18+) parahttpCheck. - Los drivers de DB/cache/broker se cargan en runtime desde el
node_modulesde la app (marcadosexternal), nunca se empaquetan endist/.
