Health Check Protocol
Connectum implements the gRPC Health Checking Protocol with additional HTTP endpoints for load balancers and Kubernetes integration.
Configuration
The Healthcheck() factory function accepts the following options:
Healthcheck({
httpEnabled: true, // Enable HTTP health endpoints
httpPaths: ['/healthz', '/health', '/readyz'], // HTTP endpoint paths
watchInterval: 500, // Watch polling interval (ms)
manager: customManager, // Custom manager instance
})Use httpEnabled and httpPaths for platform endpoints, watchInterval for the stream polling cadence, and manager when a test or multi-server process must avoid the singleton. See HealthcheckOptions for the exact field types and defaults.
The healthcheckManager Singleton
The healthcheckManager is a global singleton you import from anywhere in your application to update service health status:
import { healthcheckManager, ServingStatus } from '@connectum/healthcheck';
// Update overall health status
healthcheckManager.update(ServingStatus.SERVING);
// Update a specific service's health status
healthcheckManager.update(ServingStatus.SERVING, 'my.service.v1.MyService');
// Mark as unhealthy
healthcheckManager.update(ServingStatus.NOT_SERVING);ServingStatus Values
| Status | Value | Description |
|---|---|---|
UNKNOWN | 0 | Status is unknown (initial state) |
SERVING | 1 | Service is healthy and accepting requests |
NOT_SERVING | 2 | Service is unhealthy or draining connections |
SERVICE_UNKNOWN | 3 | Requested service is not registered |
Manager Methods
| Method | Description |
|---|---|
update(status, service?) | Update status. Without service, updates all registered entries (services and components). Throws on an unknown name. |
register(component, initialStatus?) | Register an application health component (default UNKNOWN). Re-registering preserves the current status. |
set(component, status) | Set a component's status (upsert: registers the component if absent). |
unregister(component) | Remove a registered component. |
getStatus(service) | Get status of a specific service or component. Returns ServiceStatus | undefined (undefined for an unknown name — does not throw). |
getAllStatuses() | Get a Map of all service and component statuses |
areAllHealthy() | Check if all services and components report SERVING |
initialize(serviceNames) | Initialize the RPC service slice (called by the protocol's setup, before its first register; in-process transports do not re-run it, a retry after a failed route materialization does). Replaces only service entries; never touches components. |
clear() | Clear all services and components |
gRPC Health Check Protocol
The package implements three gRPC methods on the grpc.health.v1.Health service:
The grpcurl commands below require Reflection() and a plaintext HTTP/2 listener (allowHTTP1: false). See Server reflection for setup. Use the HTTP examples with the default plaintext HTTP/1.1 listener.
Health.Check
Returns the current health status:
# Check overall health
grpcurl -plaintext localhost:5000 grpc.health.v1.Health/Check
# Check a specific service
grpcurl -plaintext \
-d '{"service": "my.service.v1.MyService"}' \
localhost:5000 grpc.health.v1.Health/CheckHealth.Watch
Streams health status changes in real time:
grpcurl -plaintext localhost:5000 grpc.health.v1.Health/WatchBehavior follows the gRPC specification:
- Immediately sends the current status
- Sends updates only when the status changes
- For unknown services, sends
SERVICE_UNKNOWN(does not terminate the call) - Terminates when the client disconnects
Health.List
List is part of the gRPC health protocol, alongside Check and Watch. It returns a snapshot of the tracked service statuses.
Lists all tracked services with their statuses. Healthcheck tracks the services mounted before it in protocols; a service that is only declared — for example next to a mounted service in the same .proto file — is not tracked, and Check answers NOT_FOUND for it:
grpcurl -plaintext localhost:5000 grpc.health.v1.Health/ListHTTP Health Endpoints
When httpEnabled: true, the following HTTP endpoints are available:
Default Endpoints
| Path | Description |
|---|---|
/healthz | Overall health status |
/health | Overall health status (alias) |
/readyz | Overall health status (alias; no separate readiness state) |
Response Format
{
"status": "SERVING",
"service": "overall",
"timestamp": "2026-02-12T10:30:00.000Z"
}HTTP Status Codes
| ServingStatus | HTTP Code |
|---|---|
SERVING | 200 OK |
NOT_SERVING | 503 Service Unavailable |
UNKNOWN | 503 Service Unavailable |
SERVICE_UNKNOWN | 404 Not Found |
Check a Specific Service via HTTP
curl http://localhost:5000/healthz?service=my.service.v1.MyServiceCustom Paths
Healthcheck({
httpEnabled: true,
httpPaths: ['/healthz', '/ready', '/live'],
})Custom Dependency Health Checks
Monitor downstream dependencies (databases, external APIs) alongside your service health:
import { healthcheckManager, ServingStatus } from '@connectum/healthcheck';
// Application components survive the protocol's RPC-service initialization.
// Component names must be non-empty and contain no dots.
healthcheckManager.register('database');
healthcheckManager.register('cache');
// Periodically check database health
setInterval(async () => {
try {
await db.ping();
healthcheckManager.set('database', ServingStatus.SERVING);
} catch {
healthcheckManager.set('database', ServingStatus.NOT_SERVING);
}
}, 10000);
// Check cache health
setInterval(async () => {
try {
await redis.ping();
healthcheckManager.set('cache', ServingStatus.SERVING);
} catch {
healthcheckManager.set('cache', ServingStatus.NOT_SERVING);
}
}, 10000);Start these checks only when the dependencies are connected, and clear their intervals in a shutdown hook. Mark each RPC service SERVING separately in the ready listener: an unqualified update(SERVING) also marks dependency components healthy, even before their checks succeed.
Worker-only processes
A process with no RPC services (services: []) still needs an explicit readiness source, because an empty registry is never healthy. Register a component before start() and flip it with the server lifecycle:
import { createServer } from '@connectum/core';
import { Healthcheck, healthcheckManager, ServingStatus } from '@connectum/healthcheck';
const server = createServer({
services: [],
port: 5000,
protocols: [Healthcheck({ httpEnabled: true })],
});
healthcheckManager.register('process');
server.on('ready', () => healthcheckManager.set('process', ServingStatus.SERVING));
server.on('stopping', () => healthcheckManager.set('process', ServingStatus.NOT_SERVING));
await server.start();/healthz then returns 200 once the component is SERVING, and gRPC Check for process reports the same status, which is what a docker compose service_healthy condition or a Kubernetes probe needs.
Use areAllHealthy() for aggregate health status:
curl http://localhost:5000/healthz
# Returns 503 if ANY dependency reports NOT_SERVINGIsolated Manager for Testing
Use createHealthcheckManager() to create isolated instances for tests or multi-server setups:
Import the runner from bun:test instead of node:test and run the file with bun test.
import { describe, it } from 'node:test';
import assert from 'node:assert';
import {
Healthcheck,
createHealthcheckManager,
ServingStatus,
} from '@connectum/healthcheck';
import { createServer } from '@connectum/core';
describe('health check', () => {
it('should track service status', () => {
const manager = createHealthcheckManager();
manager.initialize(['my.service.v1.MyService']);
manager.update(ServingStatus.SERVING, 'my.service.v1.MyService');
assert.ok(manager.areAllHealthy());
manager.update(ServingStatus.NOT_SERVING, 'my.service.v1.MyService');
assert.ok(!manager.areAllHealthy());
});
it('should work with createServer', async () => {
const manager = createHealthcheckManager();
const server = createServer({
services: [routes],
protocols: [Healthcheck({ httpEnabled: true, manager })],
});
server.on('ready', () => {
manager.update(ServingStatus.SERVING);
});
await server.start();
// ... test assertions ...
await server.stop();
});
});Related
- Health Checks Overview -- back to overview
- Kubernetes Integration -- probes, graceful shutdown, shutdown timeline
- @connectum/healthcheck -- Package Guide
- @connectum/healthcheck API -- Full API Reference