Skip to content

Commit

Permalink
feat(browser-service): add HTTP module and routes, including health c…
Browse files Browse the repository at this point in the history
…hecks and error handling
  • Loading branch information
wermarter committed Dec 24, 2024
1 parent 88e8327 commit 20c08f8
Show file tree
Hide file tree
Showing 25 changed files with 246 additions and 34 deletions.
1 change: 1 addition & 0 deletions apps/browser-service/.env.local
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
GRPC_PORT=50051
HTTP_PORT=5001
NODE_ENV=development
SERVICE_NAME=browser-service

Expand Down
3 changes: 3 additions & 0 deletions apps/browser-service/k8s/helm-chart/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ spec:
- name: grpc
containerPort: {{ .Values.service.port }}
protocol: TCP
- name: http
containerPort: 5001
protocol: TCP
envFrom:
{{- toYaml .Values.envFrom | nindent 12 }}
# livenessProbe:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
apiVersion: gateway.networking.k8s.io/v1alpha2
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: browser-service
Expand All @@ -17,6 +17,12 @@ spec:
- method:
service: diut.BrowserService
method: PrintMultiplePage
- method:
service: diut.BrowserService
method: TestTimeout
- method:
service: diut.BrowserService
method: TestError
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
Expand Down
22 changes: 22 additions & 0 deletions apps/browser-service/k8s/helm-chart/templates/http-route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: browser-service
namespace: infra
spec:
parentRefs:
- kind: Gateway
name: gateway-external
namespace: envoy-gateway-system
sectionName: http
rules:
- timeouts:
request: "60s"
backendRequest: "60s"
matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: browser-service
port: 5001
4 changes: 4 additions & 0 deletions apps/browser-service/k8s/helm-chart/templates/service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@ spec:
targetPort: grpc
protocol: TCP
name: grpc
- port: 5001
targetPort: http
protocol: TCP
name: http
selector:
{{- include "this.selectorLabels" . | nindent 4 }}
1 change: 1 addition & 0 deletions apps/browser-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@nestjs/config": "^3.2.0",
"@nestjs/core": "^10.3.3",
"@nestjs/microservices": "^10.3.3",
"@nestjs/terminus": "^10.2.3",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.48.0",
"@opentelemetry/core": "1.25.1",
Expand Down
4 changes: 2 additions & 2 deletions apps/browser-service/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common'
import { GrpcModule } from './controller'
import { GrpcModule, HttpModule } from './controller'

@Module({
imports: [GrpcModule],
imports: [GrpcModule, HttpModule],
})
export class AppModule {}
4 changes: 4 additions & 0 deletions apps/browser-service/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export class AppConfig {
@IsNumber()
GRPC_PORT: number

@Expose()
@IsNumber()
HTTP_PORT: number

@Expose()
@MinLength(3)
@IsString()
Expand Down
11 changes: 11 additions & 0 deletions apps/browser-service/src/controller/grpc/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import {
PrintPageReply,
PrintPageRequest,
} from '@diut/services'
import { Controller } from '@nestjs/common'
import { Observable, concatMap } from 'rxjs'
import { BrowserPrintMultipleUseCase } from 'src/app/browser/use-case/print-multiple'
import { setTimeout } from 'timers/promises'
import { PrintPageRequestDto } from './dto/print-page.request-dto'
import { validateDto } from './shared'

@Controller()
@BrowserServiceControllerMethods()
export class BrowserServiceController implements IBrowserServiceController {
constructor(
Expand All @@ -29,4 +32,12 @@ export class BrowserServiceController implements IBrowserServiceController {

return { mergedPdf }
}

async testTimeout(): Promise<void> {
return setTimeout(120_000)
}

async testError(): Promise<void> {
throw new Error('test error')
}
}
39 changes: 39 additions & 0 deletions apps/browser-service/src/controller/http/health/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { InjectPuppeteerService, PuppeteerService } from '@diut/nestjs-infra'
import { Controller, Get, UseFilters } from '@nestjs/common'
import {
HealthCheck,
HealthCheckResult,
HealthCheckService,
} from '@nestjs/terminus'
import { setTimeout } from 'timers/promises'
import { AllExceptionsFilter } from '../shared/exception-filter'

@Controller('health')
@UseFilters(AllExceptionsFilter)
export class HealthController {
constructor(
private readonly health: HealthCheckService,
@InjectPuppeteerService()
private readonly puppeteerClient: PuppeteerService,
) {}

@Get('liveness')
@HealthCheck()
async liveness() {
const result: HealthCheckResult = await this.health.check([
() => this.puppeteerClient.healthcheck(),
])

return result
}

@Get('error')
async error() {
throw new Error('Error')
}

@Get('timeout')
async timeout() {
return setTimeout(120_000)
}
}
1 change: 1 addition & 0 deletions apps/browser-service/src/controller/http/health/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module'
8 changes: 8 additions & 0 deletions apps/browser-service/src/controller/http/health/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ModuleMetadata } from '@nestjs/common'
import { TerminusModule } from '@nestjs/terminus'
import { HealthController } from './controller'

export const healthModuleMetadata: ModuleMetadata = {
imports: [TerminusModule],
controllers: [HealthController],
}
1 change: 1 addition & 0 deletions apps/browser-service/src/controller/http/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module'
7 changes: 7 additions & 0 deletions apps/browser-service/src/controller/http/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { concatModuleMetadata } from '@diut/nestjs-infra'
import { Module } from '@nestjs/common'
import { healthModuleMetadata } from './health'
import { commonModuleMetadata } from './shared'

@Module(concatModuleMetadata([...commonModuleMetadata, healthModuleMetadata]))
export class HttpModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
HttpStatus,
Logger,
} from '@nestjs/common'
import { HttpAdapterHost } from '@nestjs/core'

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private logger = new Logger(this.constructor.name)

constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

catch(exception: unknown, host: ArgumentsHost) {
const { httpAdapter } = this.httpAdapterHost
const ctx = host.switchToHttp()

const httpStatus =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR
const message = String(exception)

this.logger.error({
message,
httpStatus,
})

const responseBody = {
message,
}

httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus)
}
}
1 change: 1 addition & 0 deletions apps/browser-service/src/controller/http/shared/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './module'
10 changes: 10 additions & 0 deletions apps/browser-service/src/controller/http/shared/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ModuleMetadata } from '@nestjs/common'
import { appMetadata } from 'src/app'
import { configMetadata } from 'src/config'
import { infraMetadata } from 'src/infra'

export const commonModuleMetadata: ModuleMetadata[] = [
configMetadata,
infraMetadata,
appMetadata,
]
1 change: 1 addition & 0 deletions apps/browser-service/src/controller/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './grpc'
export * from './http'
41 changes: 26 additions & 15 deletions apps/browser-service/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,48 @@
import './otel'
//
import {
GrpcListenBootstrap,
HttpListenBootstrap,
LifecycleBootstrap,
PinoBootstrapFactory,
PrefixBootstrap,
bootstrapApp,
} from '@diut/nestjs-infra'
import {
DIUT_PACKAGE_NAME,
DiutGrpcService,
resolveProtoPath,
} from '@diut/services'
import { INestMicroservice } from '@nestjs/common'
import { INestApplication } from '@nestjs/common'
import { NestFactory } from '@nestjs/core'
import { MicroserviceOptions, Transport } from '@nestjs/microservices'
import * as dotenv from 'dotenv'
import { AppModule } from './app.module'

dotenv.config()

bootstrapApp<INestMicroservice>(
(AppModule, options) =>
NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
...options,
transport: Transport.GRPC,
options: {
url: `0.0.0.0:${process.env.GRPC_PORT}`,
package: DIUT_PACKAGE_NAME,
protoPath: resolveProtoPath(DiutGrpcService.Browser, __dirname),
maxReceiveMessageLength: 20_000_000,
},
}),
bootstrapApp<INestApplication>(
(AppModule, options) => NestFactory.create(AppModule, options),
AppModule,
{ serviceName: process.env.SERVICE_NAME, nodeEnv: process.env.NODE_ENV },
[PinoBootstrapFactory(), LifecycleBootstrap, GrpcListenBootstrap],
[
PinoBootstrapFactory(),
LifecycleBootstrap,
{
async afterInit(ctx) {
ctx.app.connectMicroservice<MicroserviceOptions>({
transport: Transport.GRPC,
options: {
url: `0.0.0.0:${process.env.GRPC_PORT}`,
package: DIUT_PACKAGE_NAME,
protoPath: resolveProtoPath(DiutGrpcService.Browser, __dirname),
maxReceiveMessageLength: 20_000_000,
},
})

await ctx.app.startAllMicroservices()
},
},
PrefixBootstrap,
HttpListenBootstrap(process.env.HTTP_PORT),
],
)
19 changes: 9 additions & 10 deletions apps/hcdc-access-service/k8s/helm-chart/templates/http-route.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ spec:
name: gateway-external
namespace: envoy-gateway-system
sectionName: http
hostnames:
- lab.hcdc.vn
rules:
- timeouts:
request: "60s"
backendRequest: "60s"
hostnames:
- lab.hcdc.vn
rules:
- matches:
- path:
type: PathMatchPrefix
value: /api
backendRefs:
- name: hcdc-access-service
port: 5000
matches:
- path:
type: PathMatchPrefix
value: /api
backendRefs:
- name: hcdc-access-service
port: 5000
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export const HttpListenBootstrap: (
try {
await ctx.app.listen(port)
break
} catch {
} catch (e) {
console.warn(e)
await setTimeout(1000)
}
}
Expand Down
14 changes: 13 additions & 1 deletion libs/services/src/grpc/browser-service.ts

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

Loading

0 comments on commit 20c08f8

Please sign in to comment.