No description
|
Some checks failed
Build and Publish / build-and-publish (push) Failing after 42s
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .githooks | ||
| .turbo | ||
| scripts | ||
| src | ||
| .gitignore | ||
| eslint.config.js | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsup.config.ts | ||
@lilith/nestjs-health
NestJS health check utilities with Kubernetes-compatible probes and service discovery.
Features
- Base Controller: Abstract health controller with standard endpoints
- Kubernetes Probes: Liveness, readiness, and detailed health checks
- Dependency Checks: Framework for checking database, cache, and external services
- Service Discovery: Decorator for discoverable services
- Memory Metrics: Detailed memory usage in health responses
Installation
pnpm add @lilith/nestjs-health
Peer Dependencies
pnpm add @nestjs/common @nestjs/core
Quick Start
Create a health controller by extending BaseHealthController:
import { Controller } from '@nestjs/common';
import {
BaseHealthController,
DependencyHealth,
HealthStatus,
} from '@lilith/nestjs-health';
@Controller()
export class HealthController extends BaseHealthController {
constructor(
private readonly db: DatabaseService,
private readonly cache: CacheService,
) {
super();
}
protected getVersion(): string {
return process.env.APP_VERSION || '1.0.0';
}
protected getEnvironment(): string {
return process.env.NODE_ENV ?? 'development';
}
protected async checkDependencies(): Promise<DependencyHealth[]> {
return [
await this.checkDatabase(),
await this.checkCache(),
];
}
private async checkDatabase(): Promise<DependencyHealth> {
const start = Date.now();
try {
await this.db.ping();
return {
name: 'database',
status: HealthStatus.OK,
latency: Date.now() - start,
};
} catch (error) {
return {
name: 'database',
status: HealthStatus.UNHEALTHY,
message: error.message,
};
}
}
private async checkCache(): Promise<DependencyHealth> {
const start = Date.now();
try {
await this.cache.ping();
return {
name: 'cache',
status: HealthStatus.OK,
latency: Date.now() - start,
};
} catch (error) {
return {
name: 'cache',
status: HealthStatus.DEGRADED,
message: 'Cache unavailable, using fallback',
};
}
}
}
Endpoints
The base controller provides these endpoints:
| Endpoint | Description |
|---|---|
GET /health |
Full health check with dependencies |
GET /health/live |
Liveness probe (always returns alive) |
GET /health/ready |
Readiness probe (checks dependencies) |
GET /health/detailed |
Full health + memory metrics |
Response Examples
GET /health
{
"status": "ok",
"version": "1.0.0",
"uptime": 3600,
"timestamp": "2024-01-01T12:00:00.000Z",
"environment": "production",
"dependencies": [
{
"name": "database",
"status": "ok",
"latency": 5
},
{
"name": "cache",
"status": "ok",
"latency": 2
}
]
}
GET /health/live
{
"status": "alive"
}
GET /health/ready
{
"status": "ready",
"ready": true
}
GET /health/detailed
{
"status": "ok",
"version": "1.0.0",
"uptime": 3600,
"timestamp": "2024-01-01T12:00:00.000Z",
"environment": "production",
"dependencies": [...],
"memory": {
"heapUsed": 50000000,
"heapTotal": 100000000,
"external": 1000000,
"rss": 120000000
},
"metadata": {}
}
Types
HealthStatus
enum HealthStatus {
OK = 'ok',
DEGRADED = 'degraded',
UNHEALTHY = 'unhealthy',
}
DependencyHealth
interface DependencyHealth {
name: string;
status: HealthStatus;
latency?: number; // Response time in ms
message?: string; // Error or status message
}
HealthResponse
interface HealthResponse {
status: HealthStatus;
version: string;
uptime: number; // Seconds since start
timestamp: Date;
environment: string;
dependencies: DependencyHealth[];
memory?: MemoryInfo;
metadata?: Record<string, unknown>;
}
Service Discovery
Use the @Discoverable() decorator to mark services for discovery:
import { Controller } from '@nestjs/common';
import { Discoverable } from '@lilith/nestjs-health';
@Controller()
@Discoverable({
name: 'user-service',
version: '1.0.0',
tags: ['api', 'users'],
})
export class UserController {
// ...
}
Getting Discoverable Metadata
import { getDiscoverableMetadata } from '@lilith/nestjs-health';
const metadata = getDiscoverableMetadata(UserController);
// { name: 'user-service', version: '1.0.0', tags: ['api', 'users'] }
Override Methods
Customize the health controller by overriding methods:
@Controller()
export class HealthController extends BaseHealthController {
// Required: Return your app version
protected getVersion(): string {
return '1.0.0';
}
// Optional: Override environment detection
protected getEnvironment(): string {
return process.env.NODE_ENV ?? 'development';
}
// Optional: Add dependency health checks
protected async checkDependencies(): Promise<DependencyHealth[]> {
return [];
}
// Optional: Add custom metadata to detailed response
protected getMetadata(): Record<string, unknown> {
return {
nodeVersion: process.version,
hostname: os.hostname(),
};
}
}
License
MIT