Java >> Java Tutorial >  >> Java

Hinzufügen von Integritätsprüfungen in der NestJS-Anwendung

Der Endpunkt der Zustandsprüfung enthält die Details zur Leistung unserer Anwendung. In diesem Beitrag zeigen wir, wie Sie Ihrer NestJS-Anwendung Zustandsprüfungen hinzufügen. Wenn Sie mehr über die Aktivierung von CORS in Ihrer NestJS-Anwendung erfahren möchten, können Sie hier mehr darüber lesen.

Warum Zustandsprüfungen hinzufügen?

Nachdem Sie Ihre Anwendung erstellt und bereitgestellt haben, müssen Sie auf einfachere Weise wissen, ob Ihre Anwendung reibungslos läuft, ohne einige Aufrufe der Geschäftslogik der Anwendung durchzuführen. Zustandsprüfungen bieten eine Möglichkeit zu überprüfen, ob die Datenbank reibungslos läuft, Ihre Speicherfestplatte in Ordnung ist und Ihr Anwendungsdienst wie vorgesehen ausgeführt wird.

Der wichtigste Grund, warum Sie Zustandsprüfungen benötigen, ist, dass Sie Ihre Anwendung weiterhin überwachen können. Ein Metrikerfassungsdienst (wie Micrometer) kann die Anwendung weiterhin validieren. Es kann überprüfen, ob keine Software- oder Hardwarefehler vorliegen. Jederzeit, wenn ein Software- oder Hardwarefehler auftritt, kann dies eine Benachrichtigung für einen manuellen oder automatischen Eingriff auslösen, um die Anwendung wieder in Gang zu bringen. Dies verbessert die Zuverlässigkeit der Anwendung.

Zustandsprüfungen in der NestJS-Anwendung

Im NestJS-Framework Terminus Die Bibliothek bietet eine Möglichkeit, Readiness/Liveness Health Checks zu integrieren. Ein Dienst oder eine Komponente der Infrastruktur trifft kontinuierlich auf einen GET-Endpunkt. Der Dienst ergreift basierend auf der Antwort Maßnahmen.

Lass uns anfangen. Wir werden die Terminusbibliothek zu unserer NestJS-Anwendung hinzufügen.

npm install @nestjs/terminus .

Die Terminus-Integration bietet ein ordnungsgemäßes Herunterfahren sowie eine Kubernetes-Bereitschafts-/Aktivitätsprüfung für HTTP-Anwendungen. Die Lebendigkeitsprüfung zeigt an, ob der Container betriebsbereit ist. Eine Bereitschaftsprüfung zeigt an, ob der Container bereit ist, eingehende Anfragen anzunehmen.

Wir werden in diesem Beitrag auch eine Reihe von Prüfungen für Datenbank, Speicher, Festplatte und Redis einrichten, um zu zeigen, wie Zustandsprüfungen funktionieren.

Wie richte ich eine Gesundheitsprüfung in NestJS ein?

Sobald wir nestjs/terminus hinzugefügt haben -Paket können wir einen Health-Check-Endpunkt erstellen und einige vordefinierte Indikatoren hinzufügen. Zu diesen Indikatoren gehört HTTP check , Database connectivity check , Memory and Disk check .

Je nachdem, welches ORM Sie verwenden, nestjs bietet einige eingebaute Pakete wie TypeORM oder Sequlize Health-Check-Indikatoren.

Der Gesundheitscheck liefert uns eine Kombination von Indikatoren. Dieser Satz von Indikatoren liefert uns Informationen, die uns zeigen, wie unsere Anwendung abschneidet.

DiskHealthIndicator

Beginnen wir damit, wie sich die Festplatte des Servers verhält.

DiskHealthIndicator enthält die Überprüfung des Festplattenspeichers der aktuellen Maschine.

Sobald wir DiskHealthIndicator hinzufügen In unserem Health Controller prüfen wir die Speicherung wie folgt:

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

HttpHealthIndicator

HttpHealthIndicator liefert die Details unserer HTTP-Anwendung und ob sie aktiv ist. Explizit fügen wir @nestjs/axios hinzu Paket zu unserem Projekt.

npm install @nestjs/axios .

Zusätzlich. wir werden pingCheck verwenden Methode, um zu überprüfen, ob wir eine Verbindung zur Anwendung herstellen können.

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

MemoryHealthIndikator

Insgesamt stellt MemoryHealthIndicator die Details des Arbeitsspeichers des Computers bereit, auf dem die Anwendung ausgeführt wird.

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

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

Datenbankzustandsprüfung

Angenommen, Ihre Anwendung verwendet eine Datenbank, benötigen Sie eine Datenbankintegritätsprüfung. Anschließend  nestjs/terminus bietet Datenbank-Zustandsprüfung durch ORM-Pakete wie TypeORM, Sequelize oder Mongoose. Als Teil dieser Demo erstellen wir eine benutzerdefinierte Datenbank-Zustandsprüfung, da wir Prisma ORM verwenden.

NestJS-Anwendung

Lassen Sie uns auf jeden Fall eine nestjs-Anwendung mit nestjs/cli erstellen .

nest new healthcheckdemo .

Wie bereits erwähnt, verwenden wir Prisma ORM.

npm install prisma --save-dev .

Dadurch wird Prisma CLI installiert. Wenn wir jetzt npx prisma init ausführen , wird ein Barebone von schema.prisma erstellt Datei, in der wir unser Datenbankmodellschema erstellen.

In dieser Anwendung verwende ich ein einfaches Schema, bei dem sich ein Benutzer anmelden kann, um Beiträge zu erstellen. Ich verwende auch die MySQL-Datenbank. Dieses Schema sieht wie folgt aus:

// 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?
}

Standardmäßig erstellt Prisma .env Datei, falls sie vorher noch nicht da war. Außerdem wird eine Standardvariable für DATABASE_URL hinzugefügt .

Wenn wir npm run prisma migrate dev ausführen , werden diese Datenbanktabellen in unserer DB erstellt.

Lassen Sie uns außerdem ein App-Modul in unserer Beispielanwendung für healthcheckdemo erstellen .

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 {}

Wir werden auch ein HealthModule erstellen, das dem HealthController dient.

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 {}

In diesem HealthModule werden Sie feststellen, dass es PrismaOrmHealthIndicator gibt. Bevor wir in PrismaOrmHealthIndicator eintauchen , müssen wir Prisma Client generieren .

npm install @prisma/client generiert den Prisma-Client für Ihr Datenbankmodell. Dadurch werden CRUD-Vorgänge für Ihr Datenbankmodell verfügbar gemacht, sodass sich Entwickler leichter auf die Geschäftslogik konzentrieren können, anstatt auf Daten aus einer Datenbank zuzugreifen.

Wir werden Prisma-Client-APIs abstrahieren, um Datenbankabfragen in einem separaten Dienst PrismaService zu erstellen . Dieser Dienst wird auch Prisma Client instanziieren.


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();
    });
  }
}

Es gibt ein dokumentiertes Problem mit enableShutdownHooks. Wir verwenden enableShutdownHooks aufrufen, wenn die Anwendung geschlossen wird.

Gesundheitskontrolleur

Für einen Health Check benötigen wir einen Health Controller. Wir haben im vorherigen Abschnitt über das Gesundheitsmodul gesprochen. Es bleiben noch zwei wichtige Teile, bevor wir zeigen, wie die Gesundheitsprüfung aussehen wird.

Lassen Sie uns einen Integritätscontroller erstellen.

nest g controller health

Dadurch wird ein Controller für uns generiert.

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
    ]);
  }
}

Im Health Controller haben wir einen GET-Endpunkt /health um Details zur Leistung unserer Anwendung, des Arbeitsspeichers der Maschine, der Speicherfestplatte und der Datenbanken bereitzustellen. NestJs bieten keinen ORM-Gesundheitsindikator für Prisma an. Also schreibe ich einen benutzerdefinierten Indikator, um den Zustand der Datenbank herauszufinden.

Im Großen und Ganzen wird dieser benutzerdefinierte Prisma-Zustandsindikator wie folgt aussehen:


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);
        }
    }
}

Wir erweitern die abstrakte Klasse HealthIndicator und Implementieren einer Methode namens pingCheck in diesem PrismaOrmHealthIndicator Klasse. Diese Methode verwendet PrismaService um die übergebene Datenbank abzufragen. Wir verwenden SELECT 1 Anfrage. Wenn die Abfrage erfolgreich ist, erhalten wir den Datenbankstatus als true .

Beachten Sie außerdem, dass diese Klasse PrismaOrmHealthIndicator ist injizierbar und wir injizieren das in unseren HealthController .

Wenn wir nun die Anwendung starten und den Endpunkt ausführen, erhalten wir die folgende Antwort:


{
  "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"
    }
  }
}

Wie Sie sehen können, scheint alles in Ordnung zu sein. healthcheckdemo ist der Datenbankname, den ich in MySQL verwende.

Ebenso können wir auch redis hinzufügen und mongoose als Teil von Integritätsprüfungen in unserer NestJS-Anwendung.

Schlussfolgerung

In diesem Beitrag erstellen wir eine einfache NestJS-Anwendung, um zu demonstrieren, wie Zustandsprüfungen hinzugefügt werden. Den Code für diesen Beitrag finden Sie hier.

Wenn Sie Feedback zu diesem Beitrag ODER zu meinem Buch Simplifying Spring Security haben, würde ich mich über Ihr Feedback freuen.


Java-Tag