Health
Contract
@modularityjs/health defines the HealthIndicator interface, HealthService, and pool-based indicator discovery.
interface HealthIndicator {
readonly name: string;
check(): Promise<HealthStatus>;
}interface HealthStatus {
healthy: boolean;
details?: Record<string, unknown>;
}interface AggregatedHealth {
healthy: boolean;
indicators: Record<string, HealthStatus>;
}Setup
import { HealthModule } from '@modularityjs/health';
const modules = [HealthModule];No driver is required — HealthModule declares the HealthIndicatorsPool contract and provides HealthService. Indicators are contributed by other modules.
Defining Indicators
Implement the HealthIndicator interface and register via HealthIndicatorsPool:
import { Inject, Injectable } from '@modularityjs/di';
import { HealthIndicatorsPool, HealthModule } from '@modularityjs/health';
import type { HealthIndicator } from '@modularityjs/health';
import { Module } from '@modularityjs/modularity';
import { DatabaseService } from './database.service.js';
@Injectable()
class DatabaseHealthIndicator implements HealthIndicator {
readonly name = 'database';
constructor(@Inject(DatabaseService) private readonly db: DatabaseService) {}
async check() {
const start = performance.now();
await this.db.ping();
const responseTimeMs = Math.round((performance.now() - start) * 100) / 100;
return { healthy: true, details: { responseTimeMs } };
}
}
@Module({
name: 'database-health',
imports: [HealthModule],
providers: [DatabaseHealthIndicator],
pools: [
{
pool: HealthIndicatorsPool,
key: 'database',
useClass: DatabaseHealthIndicator,
},
],
})
class DatabaseHealthModule {}The HealthService catches exceptions thrown by indicators and marks them as unhealthy automatically — indicators don't need their own try/catch. Each indicator is also raced against HealthConfig.indicatorTimeoutMs (default 5000); a slow indicator fails with Health check timed out rather than blocking the aggregate.
Built-in Indicators
Redis (@modularityjs/redis-health)
PING-based Redis liveness check with response time reporting. Requires @modularityjs/redis.
import { HealthModule } from '@modularityjs/health';
import { RedisHealthModule } from '@modularityjs/redis-health';
import { RedisModule } from '@modularityjs/redis';
const modules = [
RedisModule.forRoot({ host: 'localhost', port: 6379 }),
HealthModule,
RedisHealthModule,
];Programmatic Access
import { Inject, Injectable } from '@modularityjs/di';
import { HealthService } from '@modularityjs/health';
@Injectable()
class StatusController {
constructor(@Inject(HealthService) private readonly health: HealthService) {}
async getHealth() {
const result = await this.health.check();
// { healthy: true, indicators: { database: { healthy: true, details: { responseTimeMs: 2.31 } }, redis: { healthy: true, details: { responseTimeMs: 0.85 } } } }
return result;
}
}CLI
@modularityjs/health-cli adds the health:status command:
import { HealthModule } from '@modularityjs/health';
import { HealthCliModule } from '@modularityjs/health-cli';
const modules = [HealthModule, HealthCliModule];$ myapp health:status
HEALTHY
├── ✓ database (responseTimeMs: 2.31)
└── ✓ redis (responseTimeMs: 0.85)