@qrvey/health-checker
v1.2.4-1011
Published
 
Readme
@qrvey/health-checker
An health check library for validating the availability of core service dependencies like Redis, PostgreSQL, RabbitMQ, and Elasticsearch.
Installation
npm install @qrvey/health-checkerOr with yarn:
yarn add @qrvey/health-checkerSupported Health Check Types
| Service | Dependency Key |
| ------------- | -------------- |
| PostgreSQL | database |
| Redis | cache |
| RabbitMQ | eventBroker |
| Elasticsearch | warehouse |
Health Status Values
| Status | Description |
| -------- | ----------- |
| OK | The dependency is healthy and operating normally. |
| FAILED | The dependency is unhealthy. This is the only status that causes the overall health check to report FAILED. |
| VOID | The dependency is not part of the infrastructure for the current product license and is skipped. VOID dependencies are ignored when computing the overall status. |
The overall status is determined solely by the presence of FAILED dependencies. If all dependencies are OK or VOID, the overall status is OK. A VOID dependency never causes the overall status to become FAILED.
Usage
const { HealthCheckService } = require('@qrvey/health-checker');
HealthCheckService.check([
'cache',
'database',
'eventBroker',
'warehouse',
]).then((result) => {
console.log(result);
/*
{
status: 'OK',
details: {
cache: 'OK',
database: 'OK',
eventBroker: 'OK',
warehouse: 'OK'
}
}
*/
});You can also check specific dependencies only:
HealthCheckService.check(['cache']).then((result) => {
console.log(result);
/*
{
status: 'OK',
details: {
cache: 'OK'
}
}
*/
});Usage with Fastify
You can expose the health check as a simple route in your Fastify app.
Basic Example: health.routes.js
const { HealthCheckService } = require('@qrvey/health-checker');
const Fastify = require('fastify');
async function healthRoutes(fastify, _options) {
fastify.get('/health', async (_request, reply) => {
const dependencies = ['database', 'eventBroker', 'warehouse'];
const result = await HealthCheckService.check(dependencies);
const httpStatus = result.status === 'FAILED' ? 503 : 200;
return reply.code(httpStatus).send(result);
});
}
const app = Fastify({ logger: true });
app.register(healthRoutes);
app.listen({ port: 3000 });Basic Example Output
GET /health
{
"status": "OK",
"details": {
"database": "OK",
"eventBroker": "OK",
"warehouse": "OK"
}
}Validating Queue Subscriptions (Optional)
If you want to explicitly validate that your service is subscribed to one or more RabbitMQ queues, you can pass an additional params object to the check method.
fastify.get('/health', async (_request, reply) => {
const dependencies = ['eventBroker'];
const params = {
eventBroker: {
queues: ['queue_name_1', 'queue_name_2'], // these must match the configured subscriptions
},
}
const result = await HealthCheckService.check(dependencies, params);
const httpStatus = result.status === "FAILED" ? 503 : 200;
return reply.code(httpStatus).send(result);
});
#### Warehouse Health Check Failure Conditions
The warehouse checker marks the cluster as `FAILED` if any of these conditions are met:
- **CPU Usage** ≥ configured threshold (default: 85%)
- **JVM Heap Usage** ≥ configured threshold (default: 90%)
- **Disk Usage** ≥ configured threshold (default: 85%)
- **Circuit Breakers** near limit (ratio > 80%)
- **Thread Pool Rejections** detected
- **Cluster Status** is red (customizable)
- **Unassigned Shards** > 0 (customizable)
#### Environment-Specific Configurations
```js
const params = {
warehouse: {
thresholds: {
cpuUsagePercent: 90,
jvmHeapPercent: 95,
circuitBreakerPercent: 90
},
customClusterStatusCheck: (status) => status !== 'red',
skipRules: { skipUnassignedShardsCheck: true },
}
};
Sample output
GET /health
{
"status": "OK",
"details": {
"eventBroker": "OK"
}
}Warehouse Health Check Sample Outputs
Basic Success Response
GET /health
{
"status": "OK",
"details": {
"warehouse": "OK"
}
}Detailed Success Response (with returnClusterStats: true)
GET /health
{
"status": "OK",
"durationMs": 460,
"metadata": {
"checkTimestamp": "2025-10-01T15:14:21.787Z",
"clusterStats": {
"clusterName": "elasticsearch",
"status": "green",
"nodes": {
"total": 2,
"successful": 2,
"failed": 0
},
"cpuUsagePercent": 57.5,
"jvmHeapUsagePercent": 47.5,
"diskUsagePercent": 21.518163805507996,
"activePrimaryShards": 776,
"activeShards": 1552,
"relocatingShards": 0,
"initializingShards": 0,
"unassignedShards": 0,
"circuitBreakersException": false,
"threadPoolRejections": false
}
}
}Failure Response
GET /health
{
"status": "FAILED",
"details": {
"warehouse": {
"status": "FAILED",
"metadata": {
"clusterStats": {
"clusterName": "my-elasticsearch-cluster",
"status": "red",
"cpuUsagePercent": 88,
"jvmHeapUsagePercent": 95,
"diskUsagePercent": 90,
"circuitBreakersTripped": true,
"threadPoolRejections": false,
"unassignedShards": 15
},
"checkTimestamp": "2025-10-01T10:30:00.000Z"
}
}
}
}VOID Response (dependency not in product license)
When a dependency is not part of the current product license infrastructure (e.g. warehouse on an Ultra license), the check is skipped and returns VOID. This does not affect the overall status.
GET /health
{
"status": "OK",
"details": {
"cache": {
"status": "OK",
"durationMs": 12,
"metadata": {}
},
"warehouse": {
"status": "VOID",
"durationMs": 1,
"metadata": {
"checkTimestamp": "2025-10-01T10:30:00.000Z",
"errorMessage": "Health check skipped due to configuration"
}
}
}
}Other Configuration
Multi-Environment Setup
const getHealthParams = (env) => {
const baseParams = {
eventBroker: {
queues: process.env.REQUIRED_QUEUES?.split(',') || [],
},
};
if (env === 'development') {
return {
...baseParams,
warehouse: {
thresholds: {
cpuUsagePercent: 90,
jvmHeapPercent: 95,
circuitBreakerPercent: 90,
},
skipRules: { skipUnassignedShardsCheck: true },
},
};
}
if (env === 'production') {
return {
...baseParams,
warehouse: {
thresholds: {
cpuUsagePercent: 70,
jvmHeapPercent: 85,
circuitBreakerPercent: 75,
},
returnClusterStats: true,
},
};
}
return baseParams;
};
fastify.get('/health', async (_request, reply) => {
const dependencies = ['database', 'eventBroker', 'warehouse'];
const params = getHealthParams(process.env.NODE_ENV);
const result = await HealthCheckService.check(dependencies, params);
const httpStatus = result.status === 'FAILED' ? 503 : 200;
return reply.code(httpStatus).send(result);
});API Reference
HealthCheckService
The main service for performing health checks.
HealthCheckService.check(dependencies, params?)
- dependencies:
string[]- Array of dependency keys to check - params:
object- Optional parameters for specific health checkers - Returns:
Promise<HealthCheckResult>
interface HealthCheckResult {
status: 'OK' | 'FAILED' | 'VOID';
details: Record<string, any>;
}RuntimeHealthMiddleware
Middleware helper that returns 429 when runtime health is FAILED.
const { RuntimeHealthMiddleware } = require('@qrvey/health-checker');
// Express
app.use(RuntimeHealthMiddleware.express.start());
// Fastify
fastify.addHook('preHandler', RuntimeHealthMiddleware.fastify.start());Individual Health Checkers
You can also import and use individual health checkers directly:
const {
RabbitMQHealthChecker,
WarehouseHealthChecker,
DatabaseHealthChecker,
CacheHealthChecker,
} = require('@qrvey/health-checker');
// Direct usage
const warehouseResult = await WarehouseHealthChecker.check({
thresholds: { cpuUsagePercent: 70 },
});
const brokerResult = await RabbitMQHealthChecker.check({
queues: ['important-queue'],
});Environment Variables Reference
| Variable | Service | Description | Default |
| ---------------------------------------- | ------------- | ---------------------------------------------------- | ----------- |
| ELASTICSEARCH_HOST | warehouse | Elasticsearch/OpenSearch host | localhost |
| ELASTICSEARCH_PORT | warehouse | Elasticsearch port | 9200 |
| ELASTICSEARCH_PROTOCOL | warehouse | HTTP protocol | http |
| ELASTICSEARCH_AUTH_USER | warehouse | Basic Auth username (self-managed ES) | - |
| ELASTICSEARCH_AUTH_PASSWORD | warehouse | Basic Auth password (self-managed ES) | - |
| ELASTICSEARCH_TIMEOUT | warehouse | Request timeout (ms) | 5000 |
| RABBITMQ_HTTP_HOST | eventBroker | RabbitMQ management API host | - |
| RABBITMQ_USER | eventBroker | RabbitMQ username | - |
| RABBITMQ_PASSWORD | eventBroker | RabbitMQ password | - |
| HOSTNAME | eventBroker | Consumer tag hostname | - |
| RUNTIME_HEALTH_WINDOW_MS | runtimeHealth | Runtime measurement window in ms | 250 |
| RUNTIME_HEALTH_CPU_PERCENT | runtimeHealth | Runtime CPU threshold percent | 90 |
| RUNTIME_HEALTH_HEAP_PERCENT | runtimeHealth | Runtime heap threshold percent | 90 |
| RUNTIME_HEALTH_EVENT_LOOP_DELAY_MS | runtimeHealth | Runtime event loop delay threshold in ms | 200 |
| RUNTIME_HEALTH_ENABLE_CPU | runtimeHealth | Enable/disable CPU metric (false disables) | true |
| RUNTIME_HEALTH_ENABLE_HEAP | runtimeHealth | Enable/disable heap metric (false disables) | true |
| RUNTIME_HEALTH_ENABLE_EVENT_LOOP_DELAY | runtimeHealth | Enable/disable event loop metric (false disables) | true |
| RUNTIME_HEALTH_LOG_GET | runtimeHealth | Log payload returned by RuntimeHealthService.get() | false |
| RUNTIME_HEALTH_CACHE_TTL_SECONDS | runtimeHealth | Runtime middleware cache TTL in seconds | 3 |
| QRVEY_PRODUCT_TYPE | warehouse | Product license type. Only A3 (Ultra) includes warehouse infrastructure; any other value causes the warehouse health check to return VOID | - |
Development
Running Tests
Unit Tests
yarn workspace @qrvey/health-checker testIntegration Tests
Prerequisites:
- Access to a running Elasticsearch/OpenSearch instance (local or remote)
- Running Redis, RabbitMQ, and PostgreSQL services
Setup:
- Configure
integration.test.envwith your Elasticsearch credentials:
# Edit integration.test.env
ELASTICSEARCH_HOST=https://your-elasticsearch-domain.com
ELASTICSEARCH_PORT=443
ELASTICSEARCH_AUTH_USER=your_username
ELASTICSEARCH_AUTH_PASSWORD=your_password
# For AWS OpenSearch (uses AWS credentials automatically)
# ELASTICSEARCH_HOST=https://search-domain.us-west-2.es.amazonaws.com
# ELASTICSEARCH_PORT=443
# AWS_REGION=us-west-2- Start local services (Redis, RabbitMQ, PostgreSQL):
docker-compose -f integration.test.docker-compose.yml --env-file integration.test.env up -d- Run integration tests (automatically loads
integration.test.env):
yarn workspace @qrvey/health-checker test:integration- Stop local services:
docker-compose -f integration.test.docker-compose.yml down -vServices in Integration Tests
| Service | Location | Credentials |
| ------------- | --------------------- | ------------------- |
| Elasticsearch | Configure in .env | Your credentials |
| RabbitMQ | localhost:5672, 15672 | guest:guest |
| Redis | localhost:6379 | - |
| PostgreSQL | localhost:5432 | test_user:test_pass |
License
MIT
