typescript 43 lines · 6 steps

Liveness vs readiness probes in NestJS

A NestJS health controller uses Terminus indicators to expose separate liveness and readiness endpoints.

Explained by highlit
1import { Controller, Get } from '@nestjs/common';
2import {
3 HealthCheck,
4 HealthCheckService,
5 TypeOrmHealthIndicator,
6 DiskHealthIndicator,
7 MemoryHealthIndicator,
8} from '@nestjs/terminus';
9import { ConfigService } from '@nestjs/config';
10 
11@Controller('health')
12export class HealthController {
13 constructor(
14 private readonly health: HealthCheckService,
15 private readonly db: TypeOrmHealthIndicator,
16 private readonly disk: DiskHealthIndicator,
17 private readonly memory: MemoryHealthIndicator,
18 private readonly config: ConfigService,
19 ) {}
20 
21 @Get('liveness')
22 @HealthCheck()
23 checkLiveness() {
24 return this.health.check([
25 () => this.memory.checkHeap('memory_heap', 300 * 1024 * 1024),
26 ]);
27 }
28 
29 @Get('readiness')
30 @HealthCheck()
31 checkReadiness() {
32 const path = this.config.get<string>('DISK_HEALTH_PATH', '/');
33 
34 return this.health.check([
35 () => this.db.pingCheck('database', { timeout: 1500 }),
36 () =>
37 this.disk.checkStorage('storage', {
38 path,
39 thresholdPercent: 0.9,
40 }),
41 ]);
42 }
43}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Liveness should stay cheap and self-contained while readiness verifies external dependencies you rely on.
  2. 2Passing indicator checks as arrow functions lets the health service run and aggregate them lazily.
  3. 3Separating the two probes lets orchestrators restart a hung process without pulling a busy one out of rotation.

Related explainers

typescript
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';

How a JWT strategy authenticates in NestJS

authentication jwt passport
Intermediate 7 steps
javascript
const express = require('express');
const router = express.Router();
const { pool } = require('../db');
const redis = require('../redis');

Building a health check endpoint in Express

health-check timeouts promise-race
Intermediate 9 steps
typescript
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { catchError, filter, take, switchMap } from 'rxjs/operators';

Refreshing auth tokens in an Angular interceptor

http-interceptor token-refresh rxjs
Advanced 8 steps
javascript
'use client';
 
import { useEffect } from 'react';
import * as Sentry from '@sentry/nextjs';

How a Next.js error boundary recovers

error-boundary error-handling observability
Intermediate 8 steps
typescript
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';

How a GraphQL auth guard works in NestJS

authentication authorization jwt
Intermediate 7 steps
python
import os
from datetime import timedelta
 
 

Class-based config in a Flask app factory

configuration app-factory inheritance
Intermediate 7 steps

Share this explainer

Here's the card — post it anywhere.

Liveness vs readiness probes in NestJS — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code