Java >> Java tutorial >  >> Java

Tilføjelse af sundhedstjek i NestJS Application

Sundhedstjekkets slutpunkt giver detaljerne om, hvordan vores applikation klarer sig. I dette indlæg viser vi, hvordan du tilføjer sundhedstjek til din NestJS-applikation. Hvis du vil lære om aktivering af CORS i din NestJS-applikation, kan du læse mere om det her.

Hvorfor tilføje Health Checks?

Når du først har bygget og implementeret din applikation, skal du vide, om din applikation kører problemfrit på en nemmere måde uden at foretage nogle forretningslogiske applikationer. Sundhedstjek tilbyder en måde at kontrollere, om databasen kører problemfrit, din lagerdisk er i orden, og din applikationstjeneste kører efter hensigten.

Den vigtigste grund til, at du har brug for sundhedstjek, er, at du kan fortsætte med at overvåge din ansøgning. En metrikindsamlingstjeneste (som Micrometer) kan fortsætte med at validere applikationen. Det kan bekræfte, at der ikke er nogen software- eller hardwarefejl. Ethvert øjeblik, der er software- eller hardwarefejl, kan det udløse en meddelelse om manuel eller automatisk indgriben for at få applikationen tilbage på sporet. Dette forbedrer applikationens pålidelighed.

Sundhedstjek i NestJS-applikationen

I NestJS framework, Terminus Biblioteket tilbyder en måde at integrere beredskabs-/live-sundhedstjek på. En tjeneste eller komponent af infrastruktur vil løbende ramme et GET-endepunkt. Tjenesten vil handle baseret på svaret.

Lad os komme igang. Vi tilføjer terminusbiblioteket til vores NestJS-applikation.

npm install @nestjs/terminus .

Terminus-integration tilbyder yndefuld nedlukning samt Kubernetes paratheds-/liveness-tjek for http-applikationer. Liveness check fortæller, om containeren er oppe at køre. Et parathedstjek fortæller, om containeren er klar til at acceptere indgående anmodninger.

Vi vil også opsætte en række kontroller for database, hukommelse, disk og redis i dette indlæg for at vise, hvordan sundhedstjek fungerer.

Hvordan konfigurerer man et sundhedstjek i NestJS?

Når vi har tilføjet nestjs/terminus pakke, kan vi oprette et sundhedstjek-slutpunkt og inkludere nogle foruddefinerede indikatorer. Disse indikatorer inkluderer HTTP check , Database connectivity check , Memory and Disk check .

Afhængigt af hvilken ORM du bruger, nestjs tilbyder nogle indbyggede pakker som TypeORM eller Sequlize sundhedstjekindikatorer.

Sundhedstjekket vil give os en kombination af indikatorer. Dette sæt indikatorer giver os oplysninger, der indikerer, hvordan vores applikation klarer sig.

DiskHealthIndicator

Lad os starte med, hvordan serverens harddisk klarer sig.

DiskHealthIndicator indeholder kontrollen for disklagring af den aktuelle maskine.

Når vi tilføjer DiskHealthIndicator i vores sundhedskontroller vil vi tjekke for opbevaring som følger:

this.disk.checkStorage('diskStorage', { thresholdPercent: 0.5, path: 'C:\\'});

HttpHealthIndicator

HttpHealthIndicator vil give detaljerne om vores HTTP-applikation, og om den er oppe og køre. Eksplicit tilføjer vi @nestjs/axios pakke til vores projekt.

npm install @nestjs/axios .

Derudover. vi bruger pingCheck metode til at bekræfte, om vi er i stand til at oprette forbindelse til applikationen.

this.http.pingCheck('Basic check', 'http://localhost:3000');

MemoryHealthIndicator

Overordnet set giver MemoryHealthIndicator detaljerne om hukommelsen på den maskine, som applikationen kører på.

this.memory.checkHeap('memory_heap', 300*1024*1024);

this.memory.checkRSS('memory_rss',300*1024*1024);

Databasesundhedstjek

Forudsat at din applikation bruger en database, skal du have et databasesundhedstjek. Efterfølgende  nestjs/terminus leverer databasesundhedstjek gennem ORM-pakker som TypeORM, Sequelize eller Mongoose. Som en del af denne demo vil vi oprette et tilpasset databasesundhedstjek, da vi bruger Prisma ORM.

NestJS-applikation

Under alle omstændigheder, lad os oprette nestjs-applikation med nestjs/cli .

nest new healthcheckdemo .

Som tidligere nævnt vil vi bruge Prisma ORM.

npm install prisma --save-dev .

Dette vil installere Prisma cli. Hvis vi nu kører npx prisma init , vil det skabe en barebone på schema.prisma fil, hvor vi vil oprette vores databasemodelskema.

I denne applikation bruger jeg et simpelt skema, hvor en bruger kan tilmelde sig for at oprette indlæg. Jeg bruger også MySQL-databasen. Dette skema vil se ud som nedenstående:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
  engineType = "binary"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id    Int     @default(autoincrement()) @id
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @default(autoincrement()) @id
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

Som standard vil Prisma oprette .env fil, hvis den ikke var der før. Det vil også tilføje en standardvariabel for DATABASE_URL .

Hvis vi kører npm run prisma migrate dev , vil det skabe disse databasetabeller i vores DB.

Lad os desuden oprette et app-modul i vores eksempelapplikation til healthcheckdemo .

import { Module } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserService } from './user.service';
import { HealthModule } from './health/health.module';
import { HttpModule } from '@nestjs/axios';
import { PrismaService } from './prisma.service';

@Module({
  imports: [HealthModule, HttpModule],
  controllers: [AppController],
  providers: [AppService, UserService, PrismaClient, PrismaService,],
})
export class AppModule {}

Vi vil også oprette HealthModule, der tjener formålet for HealthControlleren.

import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { PrismaService } from 'src/prisma.service';

import { HealthController } from './health.controller';
import { PrismaOrmHealthIndicator } from './prismaorm.health';

@Module({
  imports: [
    TerminusModule,   
  ],
  controllers: [HealthController],
  providers: [ PrismaOrmHealthIndicator, PrismaService]
})
export class HealthModule {}

I dette HealthModule vil du bemærke, at der er PrismaOrmHealthIndicator. Før vi dykker ned i PrismaOrmHealthIndicator , skal vi generere Prisma Client .

npm install @prisma/client genererer Prisma-klienten til din databasemodel. Dette vil afsløre CRUD-operationer for din databasemodel, hvilket gør det nemmere for udviklere at fokusere på forretningslogik frem for hvordan man får adgang til data fra en database.

Vi vil abstrahere Prisma Client API'er for at oprette databaseforespørgsler i en separat tjeneste PrismaService . Denne service vil også instansiere Prisma Client.


import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on('beforeExit', async () => {
      await app.close();
    });
  }
}

Der er et dokumenteret problem med enableShutdownHooks. Vi bruger enableShutdownHooks ring, når du lukker applikationen.

Sundhedscontroller

Til et sundhedstjek skal vi have en sundhedskontrollant. Vi talte om sundhedsmodulet i det foregående afsnit. Der er to vigtige dele tilbage, før vi viser, hvordan sundhedstjekket vil se ud.

Lad os oprette en sundhedscontroller.

nest g controller health

Dette vil generere en controller til os.

import { Controller, Get, Inject } from '@nestjs/common';
import { DiskHealthIndicator, HealthCheck, HealthCheckService, HttpHealthIndicator, MemoryHealthIndicator, MicroserviceHealthIndicator } from '@nestjs/terminus';
import { PrismaOrmHealthIndicator } from './prismaorm.health';


@Controller('health')
export class HealthController {
    constructor(
        private health: HealthCheckService,
        private http: HttpHealthIndicator,
        @Inject(PrismaOrmHealthIndicator)
        private db: PrismaOrmHealthIndicator,
        private disk: DiskHealthIndicator,
        private memory: MemoryHealthIndicator,        
    ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () => this.http.pingCheck('basic check', 'http://localhost:3000'),
      () => this.disk.checkStorage('diskStorage', { thresholdPercent: 0.5, path: 'C:\\'}),
      () => this.db.pingCheck('healthcheckdemo'),
      () => this.memory.checkHeap('memory_heap', 300*1024*1024),
      () => this.memory.checkRSS('memory_rss', 300*1024*1024),
      
      // Mongoose for MongoDB check
      // Redis check
    ]);
  }
}

I sundhedscontrolleren har vi et GET-slutpunkt /health for at give detaljer om, hvordan vores applikation, maskinens hukommelse, lagerdisken og databaser klarer sig. NestJs tilbyder ikke nogen ORM Health-indikator for Prisma. Så jeg skriver en brugerdefineret indikator for at finde ud af databasens sundhed.

I det store og hele vil denne tilpassede Prisma-sundhedsindikator være:


import { Injectable, InternalServerErrorException } from "@nestjs/common";
import { HealthIndicator, HealthIndicatorResult } from "@nestjs/terminus";
import { PrismaService } from "src/prisma.service";


@Injectable()
export class PrismaOrmHealthIndicator extends HealthIndicator {
    constructor(private readonly prismaService: PrismaService) {
        super();
    }

    async pingCheck(databaseName: string): Promise {
        try {
            await this.prismaService.$queryRaw`SELECT 1`;
            return this.getStatus(databaseName, true);
        } catch (e) {
            throw new InternalServerErrorException('Prisma check failed', e);
        }
    }
}

Vi udvider den abstrakte klasse HealthIndicator og implementering af en metode kaldet pingCheck i denne PrismaOrmHealthIndicator klasse. Denne metode bruger PrismaService for at forespørge på den database, der er blevet bestået. Vi bruger SELECT 1 forespørgsel. Hvis forespørgslen lykkes, får vi databasestatus som true .

Bemærk også, at denne klasse PrismaOrmHealthIndicator er injicerbar, og vi injicerer det i vores HealthController .

Hvis vi nu starter applikationen og udfører slutpunktet, får vi svaret som nedenfor:


{
  "status": "ok",
  "info": {
    "basic check": {
      "status": "up"
    },
    "diskStorage": {
      "status": "up"
    },
    "healthcheckdemo": {
      "status": "up"
    },
    "memory_heap": {
      "status": "up"
    },
    "memory_rss": {
      "status": "up"
    }
  },
  "error": {},
  "details": {
    "basic check": {
      "status": "up"
    },
    "diskStorage": {
      "status": "up"
    },
    "healthcheckdemo": {
      "status": "up"
    },
    "memory_heap": {
      "status": "up"
    },
    "memory_rss": {
      "status": "up"
    }
  }
}

Som du kan se, ser alt ud til at køre fint. healthcheckdemo er databasenavnet, som jeg bruger i MySQL.

På samme måde kan vi også tilføje redis og mongoose som en del af sundhedstjek i vores NestJS-applikation.

Konklusion

I dette indlæg opretter vi en simpel NestJS-applikation for at demonstrere, hvordan man tilføjer sundhedstjek. Koden til dette indlæg er tilgængelig her.

Hvis du har feedback til dette indlæg ELLER min bog Simplifying Spring Security, vil jeg meget gerne høre din feedback.


Java tag