Zero Downtime Deployment / TypeScript

Today we will talk about zero downtime deployment in a Node.js application.

To make this possible, your application must be running in a child process. For example, use PM2 or ts-node-dev.

The first thing we need to do is to indicate that a new (deployed) process is ready to take over the work of the redeployed application. To do this, you need to call…

process.send(“ready”)

In your application, after all the necessary dependencies are in the ready state, such as a successful connection to the database.

Also, in our application, we need to add logic for the completion of all current operations when receiving a termination signal (SIGINT).

process.on(“SIGINT”, () => {
  this.connection.close(); // For example, we will close the current connection to AMQP and stop accepting new messages.
  setTimeout(() => {
    process.exit()
  }, 5000) // Let's wait for 5 seconds until the current processes are completed.
})

When running such an application, for example, using ts-node-dev, you may notice that after pressing control+c, the application does not terminate immediately, but after 5 seconds.

What will happen:

  • The new application launched in a child process starts and reports “ready”, after which it begins its business logic.
  • At the same time, a SIGINT signal is sent to the old process, and it enters the mode of terminating and finalizing its work, after which it is destroyed.

Example

class App {
  private isOnline = true

  public start() {
    console.log("Started")
    this.restartListener()
    this.loop()
  }

  private loop() {
    if (!this.isOnline) return
    console.log("Some business logic like redis/sql/amqp and others operation")
    this.loop()
  }

  private restartListener() {
     if (typeof process.send !== "function") return

     process.send(“ready”)
     process.on(“SIGINT”, () => {
       this.isOnline = false
       setTimeout(() => {
         process.exit()  
       }, 3000)
     })
  }

}