From ed65a99b5cc6eaa911be6a8b33bbd59f597cb3d0 Mon Sep 17 00:00:00 2001 From: kamaldeen Aliyu <133337507+Nanafancy@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:20:57 +0100 Subject: [PATCH 1/3] implemented the health check --- backend/src/opsce/health/healthController.ts | 4 ++++ backend/src/opsce/health/healthModule.ts | 11 +++++++++++ backend/src/opsce/health/healthSerivce.ts | 8 ++++++++ 3 files changed, 23 insertions(+) create mode 100644 backend/src/opsce/health/healthController.ts create mode 100644 backend/src/opsce/health/healthModule.ts create mode 100644 backend/src/opsce/health/healthSerivce.ts diff --git a/backend/src/opsce/health/healthController.ts b/backend/src/opsce/health/healthController.ts new file mode 100644 index 00000000..4920dea3 --- /dev/null +++ b/backend/src/opsce/health/healthController.ts @@ -0,0 +1,4 @@ + + + +export class healthController {} \ No newline at end of file diff --git a/backend/src/opsce/health/healthModule.ts b/backend/src/opsce/health/healthModule.ts new file mode 100644 index 00000000..1e5b68e2 --- /dev/null +++ b/backend/src/opsce/health/healthModule.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { AuditLog } from './entities/audit-log.entity'; +import { AuditService } from './audit.service'; + +@Module({ + imports: [TypeOrmModule.forFeature([])], + providers: [HealthService], + exports: [HealthService, TypeOrmModule], +}) +export class HealthModule {} diff --git a/backend/src/opsce/health/healthSerivce.ts b/backend/src/opsce/health/healthSerivce.ts new file mode 100644 index 00000000..19921615 --- /dev/null +++ b/backend/src/opsce/health/healthSerivce.ts @@ -0,0 +1,8 @@ + + +@Injectable() +export class HealthService { + getHealthStatus(): string { + return 'OK'; + } +} \ No newline at end of file From 144b9e1283d74a45b1d26f820cc844b3c67e480c Mon Sep 17 00:00:00 2001 From: kamaldeen Aliyu <133337507+Nanafancy@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:22:08 +0100 Subject: [PATCH 2/3] health check --- backend/src/opsce/health/healthController.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/opsce/health/healthController.ts b/backend/src/opsce/health/healthController.ts index 4920dea3..ab5b2c22 100644 --- a/backend/src/opsce/health/healthController.ts +++ b/backend/src/opsce/health/healthController.ts @@ -1,4 +1,11 @@ -export class healthController {} \ No newline at end of file +export class healthController { + constructor(private readonly healthService: HealthService) {} + + @Get() + getHealth(): string { + return this.healthService.getHealthStatus(); + } +} \ No newline at end of file From ccf773efc90ccde596ea2bebbf6eb009048c7aee Mon Sep 17 00:00:00 2001 From: kamaldeen Aliyu <133337507+Nanafancy@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:30:07 +0100 Subject: [PATCH 3/3] publich health check using terminus --- .../health/decorator/public-decorator.ts | 6 ++ backend/src/opsce/health/healthController.ts | 44 +++++++++++++++ backend/src/opsce/health/healthModule.ts | 15 ++--- backend/src/opsce/health/healthSerivce.ts | 55 +++++++++++++++++++ 4 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 backend/src/opsce/health/decorator/public-decorator.ts diff --git a/backend/src/opsce/health/decorator/public-decorator.ts b/backend/src/opsce/health/decorator/public-decorator.ts new file mode 100644 index 00000000..30a5a2e6 --- /dev/null +++ b/backend/src/opsce/health/decorator/public-decorator.ts @@ -0,0 +1,6 @@ +import { SetMetadata } from '@nestjs/common'; + +export const IS_PUBLIC_KEY = 'isPublic'; + +export const Public = () => + SetMetadata(IS_PUBLIC_KEY, true); \ No newline at end of file diff --git a/backend/src/opsce/health/healthController.ts b/backend/src/opsce/health/healthController.ts index ab5b2c22..db8c2b8a 100644 --- a/backend/src/opsce/health/healthController.ts +++ b/backend/src/opsce/health/healthController.ts @@ -8,4 +8,48 @@ export class healthController { getHealth(): string { return this.healthService.getHealthStatus(); } +} + + +import { + Controller, + Get, +} from '@nestjs/common'; + +import { + HealthCheck, + HealthCheckService, + TypeOrmHealthIndicator, + DiskHealthIndicator, +} from '@nestjs/terminus'; + +import { RedisHealthIndicator } from './indicators/redis.health'; +import { Public } from '../../auth/decorators/public.decorator'; + +@Controller('health') +export class HealthController { + constructor( + private readonly health: HealthCheckService, + private readonly db: TypeOrmHealthIndicator, + private readonly disk: DiskHealthIndicator, + private readonly redis: RedisHealthIndicator, + ) {} + + @Get() + @Public() + @HealthCheck() + check() { + return this.health.check([ + () => this.db.pingCheck('postgres'), + + () => + this.redis.isHealthy('redis'), + + () => + this.disk.checkStorage('storage', { + path: '/', + thresholdPercent: 0.9, + }), + ]); + } } \ No newline at end of file diff --git a/backend/src/opsce/health/healthModule.ts b/backend/src/opsce/health/healthModule.ts index 1e5b68e2..d4b1f808 100644 --- a/backend/src/opsce/health/healthModule.ts +++ b/backend/src/opsce/health/healthModule.ts @@ -1,11 +1,12 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { AuditLog } from './entities/audit-log.entity'; -import { AuditService } from './audit.service'; +import { TerminusModule } from '@nestjs/terminus'; + +import { HealthController } from './health.controller'; +import { RedisHealthIndicator } from './indicators/redis.health'; @Module({ - imports: [TypeOrmModule.forFeature([])], - providers: [HealthService], - exports: [HealthService, TypeOrmModule], + imports: [TerminusModule], + controllers: [HealthController], + providers: [RedisHealthIndicator], }) -export class HealthModule {} +export class HealthModule {} \ No newline at end of file diff --git a/backend/src/opsce/health/healthSerivce.ts b/backend/src/opsce/health/healthSerivce.ts index 19921615..5c99b3fa 100644 --- a/backend/src/opsce/health/healthSerivce.ts +++ b/backend/src/opsce/health/healthSerivce.ts @@ -5,4 +5,59 @@ export class HealthService { getHealthStatus(): string { return 'OK'; } +} + + +import { + Injectable, +} from '@nestjs/common'; + +import { + HealthIndicator, + HealthIndicatorResult, + HealthCheckError, +} from '@nestjs/terminus'; + +import Redis from 'ioredis'; + +@Injectable() +export class RedisHealthIndicator extends HealthIndicator { + private readonly redis: Redis; + + constructor() { + super(); + + this.redis = new Redis({ + host: process.env.REDIS_HOST, + port: Number(process.env.REDIS_PORT), + password: process.env.REDIS_PASSWORD, + }); + } + + async isHealthy( + key: string, + ): Promise { + try { + const response = await this.redis.ping(); + + const result = this.getStatus( + key, + response === 'PONG', + ); + + if (response !== 'PONG') { + throw new HealthCheckError( + 'Redis check failed', + result, + ); + } + + return result; + } catch (error) { + throw new HealthCheckError( + 'Redis unavailable', + this.getStatus(key, false), + ); + } + } } \ No newline at end of file