Blog

blog-zero-downtime-cover copy

Scaling your Nestjs application with Zero Downtime deployment

Tips

Scaling your Nestjs application with Zero Downtime deployment

To avoid interrupting service when building a project in NestJS and running the service with PM2, you can use several strategies. The most effective method is to use zero-downtime deployment practices.

Because rimraf dist is used before building the project, you can adopt a strategy that involves building the new version of your project in a separate directory and then performing a smooth switch.

Here’s a detailed step-by-step approach:

  1. Build in a Temporary Directory: Instead of directly building into the dist directory, build your project into a temporary directory.
  2. Use PM2 to Reload the Application: After the build is complete, use PM2 to reload the application from the new build directory.
  3. Swap Directories: Once the reload is successful, swap the dist directory with the new build directory.

Detailed Implementation

Modify Your Build Script: Adjust your build script to output to a temporary directory (e.g., dist-new). Update your package.json scripts:

{
  "scripts": {
    "prebuild": "rimraf dist-new",
    "build": "nest build"
  }
}

Modify your tsconfig.build.json to specify a different output directory.

{
  "compilerOptions": {
    "outDir": "./dist-new",  // Change to dist-new
    "rootDir": "./src",
    "module": "commonjs",
    "target": "es2017",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "strict": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
}

Deploy Script: Create a deployment script to handle the build process, directory swap, and PM2 reload. Create a deploy.sh script:

#!/bin/bash

# Step 1: Build the new version into a temporary directory
echo "Building the project..."
npm run build

# Step 2: Check if build was successful
if [ $? -ne 0 ]; then
  echo "Build failed. Exiting."
  exit 1
fi

# Step 3: Copy current dist to a backup directory
echo "Backing up current dist directory..."
mv dist dist-backup

# Step 4: Move new build to dist directory
echo "Swapping dist directories..."
mv dist-new dist

# Step 5: Reload PM2 with zero downtime
echo "Reloading PM2..."
pm2 reload all

# Step 6: Cleanup backup
echo "Cleaning up backup..."
rm -rf dist-backup

echo "Deployment completed successfully."

Make Script Executable: Ensure the deployment script is executable then run

chmod +x deploy.sh
./deploy.sh

Explanation:

  • TypeScript Configuration (tsconfig.build.json): Specifies that the output should go to a new directory (dist-new).
  • Build Script (package.json): Defines the build steps to first remove the old dist-new directory and then build the project using the specified tsconfig.
  • Deployment Script (deploy.sh): Manages the build process, directory swaps, and PM2 reloading to ensure zero downtime.

This approach ensures that the service is not interrupted during the build and deployment process. The application continues to run from the current dist directory until the new build is ready and swapped in.