import { Controller, Get, Inject, ServiceUnavailableException, } from '@nestjs/common'; import { InjectConnection } from '@nestjs/mongoose'; import { ApiOkResponse, ApiOperation, ApiServiceUnavailableResponse, ApiTags, } from '@nestjs/swagger'; import { Public } from '@task-stream/api/identity/presenters'; import { REDIS_CLIENT } from '@task-stream/api/shared/infrastructure'; import Redis from 'ioredis'; import { Connection } from 'mongoose'; import { DataSource } from 'typeorm'; @ApiTags('Health') @Controller('health') export class HealthController { constructor( private readonly postgres: DataSource, @InjectConnection() private readonly mongo: Connection, @Inject(REDIS_CLIENT) private readonly redis: Redis, ) {} @Public() @Get() @ApiOperation({ summary: 'API and databases status' }) @ApiOkResponse({ schema: { example: { status: 'ok', postgres: 'up', mongo: 'up', redis: 'up' }, }, }) @ApiServiceUnavailableResponse({ description: 'A database is down' }) async check() { const checks = await Promise.allSettled([ this.postgres.query('SELECT 1'), this.mongo.db?.admin().ping(), this.redis.ping(), ]); const [postgres, mongo, redis] = checks.map((c) => c.status === 'fulfilled' ? 'up' : 'down', ); const result = { status: 'ok', postgres, mongo, redis }; if (checks.some((c) => c.status === 'rejected')) { throw new ServiceUnavailableException({ ...result, status: 'degraded' }); } return result; } }