Skip to content

Commit ceeb76a

Browse files
authored
feat: ping + terminus health endpoints (#479)
1 parent 3504123 commit ceeb76a

10 files changed

+139
-36
lines changed

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
},
3131
"dependencies": {
3232
"@mailchimp/mailchimp_marketing": "^3.0.80",
33+
"@nestjs/axios": "^3.0.2",
3334
"@nestjs/common": "^10.3.6",
3435
"@nestjs/config": "^3.2.2",
3536
"@nestjs/core": "^10.3.6",
3637
"@nestjs/platform-express": "^10.3.7",
3738
"@nestjs/swagger": "^7.3.1",
39+
"@nestjs/terminus": "^10.2.3",
3840
"@nestjs/typeorm": "^10.0.2",
39-
"axios": "^1.6.8",
41+
"axios": "^1.7.2",
4042
"class-transformer": "^0.5.1",
4143
"class-validator": "^0.14.1",
4244
"date-fns": "^3.6.0",

src/app.controller.spec.ts

-22
This file was deleted.

src/app.controller.ts

-9
This file was deleted.

src/app.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CourseUserModule } from './course-user/course-user.module';
88
import { CourseModule } from './course/course.module';
99
import { EventLoggerModule } from './event-logger/event-logger.module';
1010
import { FeatureModule } from './feature/feature.module';
11+
import { HealthModule } from './health/health.module';
1112
import { LoggerModule } from './logger/logger.module';
1213
import { PartnerAccessModule } from './partner-access/partner-access.module';
1314
import { PartnerAdminModule } from './partner-admin/partner-admin.module';
@@ -39,6 +40,7 @@ import { WebhooksModule } from './webhooks/webhooks.module';
3940
FeatureModule,
4041
PartnerFeatureModule,
4142
EventLoggerModule,
43+
HealthModule,
4244
],
4345
})
4446
export class AppModule {}

src/health/health.controller.spec.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { HttpModule } from '@nestjs/axios';
2+
import { TerminusModule } from '@nestjs/terminus';
3+
import { Test, TestingModule } from '@nestjs/testing';
4+
import { HealthController } from './health.controller';
5+
6+
describe('HealthController', () => {
7+
let controller: HealthController;
8+
9+
beforeEach(async () => {
10+
const module: TestingModule = await Test.createTestingModule({
11+
imports: [TerminusModule, HttpModule],
12+
controllers: [HealthController],
13+
}).compile();
14+
15+
controller = module.get<HealthController>(HealthController);
16+
});
17+
18+
it('should be defined', () => {
19+
expect(controller).toBeDefined();
20+
});
21+
});

src/health/health.controller.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Controller, Get } from '@nestjs/common';
2+
import {
3+
HealthCheck,
4+
HealthCheckService,
5+
HttpHealthIndicator,
6+
TypeOrmHealthIndicator,
7+
} from '@nestjs/terminus';
8+
import { frontendAppUrl } from 'src/utils/constants';
9+
10+
@Controller('ping')
11+
export class HealthController {
12+
constructor(
13+
private readonly health: HealthCheckService,
14+
private readonly http: HttpHealthIndicator,
15+
private readonly db: TypeOrmHealthIndicator,
16+
) {}
17+
18+
@Get()
19+
@HealthCheck()
20+
ping() {
21+
return 'ok';
22+
}
23+
24+
@Get('/frontend')
25+
@HealthCheck()
26+
checkFrontend() {
27+
return this.health.check([() => this.http.pingCheck('frontend', frontendAppUrl)]);
28+
}
29+
30+
@Get('/database')
31+
@HealthCheck()
32+
checkDatabase() {
33+
return this.health.check([() => this.db.pingCheck('database')]);
34+
}
35+
}

src/health/health.module.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { HttpModule } from '@nestjs/axios';
2+
import { Module } from '@nestjs/common';
3+
import { TerminusModule } from '@nestjs/terminus';
4+
import { HealthController } from './health.controller';
5+
6+
@Module({
7+
imports: [TerminusModule, HttpModule],
8+
controllers: [HealthController],
9+
})
10+
export class HealthModule {}

src/main.ts

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ async function bootstrap() {
1313

1414
app.setGlobalPrefix('api');
1515

16+
// Starts listening for shutdown hooks
17+
app.enableShutdownHooks();
18+
1619
const options = new DocumentBuilder()
1720
.setTitle('Bloom backend API')
1821
.setDescription('Bloom backend API')

src/utils/constants.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export enum ENVIRONMENTS {
5757
DEVELOPMENT = 'development',
5858
STAGING = 'staging',
5959
PRODUCTION = 'production',
60-
TESTING = 'testing',
60+
TEST = 'test',
6161
}
6262

6363
const getEnv = (env: string, envName: string): string => {
@@ -66,12 +66,13 @@ const getEnv = (env: string, envName: string): string => {
6666

6767
return env;
6868
} catch (error) {
69-
if (nodeEnv !== ENVIRONMENTS.TESTING) console.log(error);
69+
if (nodeEnv !== ENVIRONMENTS.TEST) console.log(error);
7070
}
7171
};
7272

7373
export const nodeEnv = getEnv(process.env.NODE_ENV, 'NODE_ENV');
7474
export const isProduction = nodeEnv === ENVIRONMENTS.PRODUCTION;
75+
export const frontendAppUrl = getEnv(process.env.FRONTEND_APP_URL, 'FRONTEND_APP_URL');
7576

7677
export const rollbarEnv = getEnv(process.env.ROLLBAR_ENV, 'ROLLBAR_ENV');
7778
export const rollbarToken = getEnv(process.env.ROLLBAR_TOKEN, 'ROLLBAR_TOKEN');

yarn.lock

+62-2
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,11 @@
11811181
resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb"
11821182
integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==
11831183

1184+
"@nestjs/axios@^3.0.2":
1185+
version "3.0.2"
1186+
resolved "https://registry.yarnpkg.com/@nestjs/axios/-/axios-3.0.2.tgz#0078c101a29fb46f5c566d68a4315fddabc083ed"
1187+
integrity sha512-Z6GuOUdNQjP7FX+OuV2Ybyamse+/e0BFdTWBX5JxpBDKA+YkdLynDgG6HTF04zy6e9zPa19UX0WA2VDoehwhXQ==
1188+
11841189
"@nestjs/cli@^10.3.2":
11851190
version "10.3.2"
11861191
resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.3.2.tgz#42d2764ead6633e278c55d42de871b4cc1db002b"
@@ -1279,6 +1284,14 @@
12791284
path-to-regexp "3.2.0"
12801285
swagger-ui-dist "5.11.2"
12811286

1287+
"@nestjs/terminus@^10.2.3":
1288+
version "10.2.3"
1289+
resolved "https://registry.yarnpkg.com/@nestjs/terminus/-/terminus-10.2.3.tgz#72c8a66d04df52aeaae807551245480fd7239a75"
1290+
integrity sha512-iX7gXtAooePcyQqFt57aDke5MzgdkBeYgF5YsFNNFwOiAFdIQEhfv3PR0G+HlH9F6D7nBCDZt9U87Pks/qHijg==
1291+
dependencies:
1292+
boxen "5.1.2"
1293+
check-disk-space "3.4.0"
1294+
12821295
"@nestjs/testing@^10.3.6":
12831296
version "10.3.8"
12841297
resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.3.8.tgz#44df73ede43c47801400d59a8ebd6ab1fe7df34c"
@@ -2125,6 +2138,13 @@ ajv@^8.0.0:
21252138
require-from-string "^2.0.2"
21262139
uri-js "^4.4.1"
21272140

2141+
ansi-align@^3.0.0:
2142+
version "3.0.1"
2143+
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
2144+
integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==
2145+
dependencies:
2146+
string-width "^4.1.0"
2147+
21282148
21292149
version "4.1.3"
21302150
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
@@ -2262,6 +2282,15 @@ axios@^1.6.8:
22622282
form-data "^4.0.0"
22632283
proxy-from-env "^1.1.0"
22642284

2285+
axios@^1.7.2:
2286+
version "1.7.2"
2287+
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
2288+
integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
2289+
dependencies:
2290+
follow-redirects "^1.15.6"
2291+
form-data "^4.0.0"
2292+
proxy-from-env "^1.1.0"
2293+
22652294
babel-jest@^29.7.0:
22662295
version "29.7.0"
22672296
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
@@ -2369,6 +2398,20 @@ [email protected]:
23692398
type-is "~1.6.18"
23702399
unpipe "1.0.0"
23712400

2401+
2402+
version "5.1.2"
2403+
resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
2404+
integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==
2405+
dependencies:
2406+
ansi-align "^3.0.0"
2407+
camelcase "^6.2.0"
2408+
chalk "^4.1.0"
2409+
cli-boxes "^2.2.1"
2410+
string-width "^4.2.2"
2411+
type-fest "^0.20.2"
2412+
widest-line "^3.1.0"
2413+
wrap-ansi "^7.0.0"
2414+
23722415
brace-expansion@^1.1.7:
23732416
version "1.1.11"
23742417
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -2539,7 +2582,7 @@ chardet@^0.7.0:
25392582
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
25402583
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
25412584

2542-
check-disk-space@^3.4.0:
2585+
check-disk-space@3.4.0, check-disk-space@^3.4.0:
25432586
version "3.4.0"
25442587
resolved "https://registry.yarnpkg.com/check-disk-space/-/check-disk-space-3.4.0.tgz#eb8e69eee7a378fd12e35281b8123a8b4c4a8ff7"
25452588
integrity sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==
@@ -2603,6 +2646,11 @@ clean-stack@^2.0.0:
26032646
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
26042647
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
26052648

2649+
cli-boxes@^2.2.1:
2650+
version "2.2.1"
2651+
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
2652+
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
2653+
26062654
cli-cursor@^3.1.0:
26072655
version "3.1.0"
26082656
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@@ -6565,7 +6613,7 @@ string-length@^4.0.1:
65656613
char-regex "^1.0.2"
65666614
strip-ansi "^6.0.0"
65676615

6568-
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
6616+
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
65696617
version "4.2.3"
65706618
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
65716619
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -7011,6 +7059,11 @@ [email protected]:
70117059
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
70127060
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
70137061

7062+
type-fest@^0.20.2:
7063+
version "0.20.2"
7064+
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
7065+
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
7066+
70147067
type-fest@^0.21.3:
70157068
version "0.21.3"
70167069
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
@@ -7293,6 +7346,13 @@ which@^4.0.0:
72937346
dependencies:
72947347
isexe "^3.1.1"
72957348

7349+
widest-line@^3.1.0:
7350+
version "3.1.0"
7351+
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
7352+
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
7353+
dependencies:
7354+
string-width "^4.0.0"
7355+
72967356
winston-transport@^4.5.0:
72977357
version "4.7.0"
72987358
resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.0.tgz#e302e6889e6ccb7f383b926df6936a5b781bd1f0"

0 commit comments

Comments
 (0)