Skip to content

Commit

Permalink
Merge pull request #4 from openfoodfacts:line-endings
Browse files Browse the repository at this point in the history
Health check
  • Loading branch information
john-gom authored Sep 15, 2023
2 parents a5ba9f6 + a3b1749 commit 2fde972
Show file tree
Hide file tree
Showing 9 changed files with 293 additions and 9 deletions.
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* text=auto eol=lf
[core]
# avoid line ending conversion on windows
autocrlf=false
149 changes: 141 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@nestjs/common": "^9.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/terminus": "^10.1.1",
"id128": "^1.6.6",
"mongodb": "^5.8.0",
"reflect-metadata": "^0.1.13",
Expand Down
3 changes: 2 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { DomainModule } from './domain/domain.module';
import { HealthModule } from './health/health.module';

@Module({
imports: [DomainModule],
imports: [DomainModule, HealthModule],
controllers: [AppController],
providers: [],
})
Expand Down
48 changes: 48 additions & 0 deletions src/health/health.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { HealthController } from './health.controller';
import { createTestingModule } from '../../test/test.helper';
import { AppModule } from '../app.module';
import { MongodbHealthIndicator } from './mongodb-health-indicator';
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
import { ServiceUnavailableException } from '@nestjs/common';

describe('HealthController', () => {
it('should return healthy', async () => {
await createTestingModule([AppModule], async (app) => {
const controller = app.get(HealthController);
expect(controller).toBeDefined();

const mongoIndicator = app.get(MongodbHealthIndicator);
mongoIndicator.isHealthy = jest.fn(async () => {
return {
mongodb: {
status: 'up',
},
} as HealthIndicatorResult;
});
const status = await controller.check();
expect(status.status).toBe('ok');
});
});

it('should return unhealthy if mongodb is down', async () => {
await createTestingModule([AppModule], async (app) => {
const controller = app.get(HealthController);

const mongoIndicator = app.get(MongodbHealthIndicator);
mongoIndicator.isHealthy = jest.fn(async () => {
throw new HealthCheckError('Mongodb check failed', {
mongodb: {
status: 'down',
},
});
});
try {
await controller.check();
fail('should not get here');
} catch (e) {
expect(e).toBeInstanceOf(ServiceUnavailableException);
expect(e.response.status).toBe('error');
}
});
});
});
22 changes: 22 additions & 0 deletions src/health/health.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Controller, Get } from '@nestjs/common';
import { HealthCheckService, HealthCheck } from '@nestjs/terminus';
import { PostgresHealthIndicator } from './postgres-health-indicator';
import { MongodbHealthIndicator } from './mongodb-health-indicator';

@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private postgres: PostgresHealthIndicator,
private mongodb: MongodbHealthIndicator,
) {}

@Get()
@HealthCheck()
check() {
return this.health.check([
() => this.postgres.isHealthy(),
() => this.mongodb.isHealthy(),
]);
}
}
13 changes: 13 additions & 0 deletions src/health/health.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Module } from '@nestjs/common';
import { HealthController } from './health.controller';
import { PostgresHealthIndicator } from './postgres-health-indicator';
import { TerminusModule } from '@nestjs/terminus';
import { DomainModule } from '../domain/domain.module';
import { MongodbHealthIndicator } from './mongodb-health-indicator';

@Module({
imports: [TerminusModule, DomainModule],
controllers: [HealthController],
providers: [PostgresHealthIndicator, MongodbHealthIndicator],
})
export class HealthModule {}
35 changes: 35 additions & 0 deletions src/health/mongodb-health-indicator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import {
HealthIndicator,
HealthIndicatorResult,
HealthCheckError,
} from '@nestjs/terminus';
import { MongoClient } from 'mongodb';

@Injectable()
export class MongodbHealthIndicator extends HealthIndicator {
NAME = 'mongodb';
async isHealthy(): Promise<HealthIndicatorResult> {
try {
const client = new MongoClient(process.env.MONGO_URI, {
serverSelectionTimeoutMS: 1000,
connectTimeoutMS: 1000,
socketTimeoutMS: 1000,
});
await client.connect();
const db = client.db('off');
const products = db.collection('products');
const cursor = products.find({}, { projection: { code: 1 } });
await cursor.next();
await cursor.close();
await client.close();

return this.getStatus(this.NAME, true);
} catch (e) {
throw new HealthCheckError(
'MongoDB check failed',
this.getStatus(this.NAME, false, e),
);
}
}
}
Loading

0 comments on commit 2fde972

Please sign in to comment.