hapi — Zero-Downtime Deployments Using PM2

The previous tutorial on how to correctly stop your hapi server already teasered another tutorial on the same topic with more focus on your production environment.

We at Future Studio are huge fans of hapi, which you can see at all the tutorials. Also, we love the awesome Node.js process manager PM2. In production, we completely rely on PM2 to run our hapi platform and both technologies work great in combination.

This tutorial shows you how to run and deploy your hapi application without downtime in production using PM2.

hapi Series Overview

  1. Zero-Downtime Deployments Using PM2

Correctly Shut Down Your Hapi Server

The mentioned tutorial on shutting down your hapi server correctly illustrates the process with just a single hapi server instance. You might wonder how it’s possible to interact with client requests and process them correctly while restarting the application? Actually, you’re right; it’s impossible to have a Schrödinger’s Server: being online and offline at the same time.

What you want is the process to finish existing requests first, response them appropriately and simultaneously don’t accept new connections so you can restart your hapi app once every open connection got closed.

So what’s the trick to restart your hapi app without downtime? If you already guessed that you’d at least require two instances of your hapi server: you’re completely correct! You need some kind of cluster where at least one instance is always able to handle requests and serve them correctly.

Prepare your Hapi Server for Zero Downtime Restarts

Before diving into the part of starting multiple hapi instances with PM2, you need to prepare your hapi server to actually be ready for zero-downtime restarts, also called graceful restarts. When receiving a signal to stop your hapi server, you need to properly close existing connections. Graceful restarts of your processes are an elegant way to keep your services available while updating the current deployment.

Therefore, install the hapi-graceful-pm2 plugin which handles the correct teardown and handling of existing requests.

server.register({  
  register: require('hapi-graceful-pm2'),
  options: {
    // the "listen_timeout" value within the PM2 process file 
    // needs to be greater or equal to this one here!
    timeout: 8000
  }
})

There’s only a single option to customize the behavior: timeout. The timeout defines the interval (in milliseconds) before hapi finally stops the server instance and cuts of all connections. If your server does some heavy lifting and executes long running tasks, make sure to increase the timeout value. If every connection is closed before the timeout, your server stops earlier and doesn’t wait for the timeout interval to expire.

Start Your hapi Application in Cluster Mode

Zero-downtime deployments require at least two instances of your applications so that in case of a restart you can shut down one after another and at each time there’s at least an instance able to accept and handle requests. You could build the cluster functionality for multiple instances yourself, but that’s not what you want. Trust me.

With PM2, there’s a great process manager doing a solid job providing the required features to manage your applications without headaches. Head over to our PM2 series to get more details. There’s a dedicated tutorial on PM2’s cluster mode and zero-downtime restarts that outlines PM2’s viewpoint on this topic. Within this tutorial, you’ll read about the hapi view of things :)

At this point, you should have installed PM2 on your server (or local machine). If you didn’t have the tool installed yet, just do it now and proceed from here.

To run your hapi app in cluster mode with at least two instances, you can either use the pm2 command line utility or define a process file. We prefer the process file because it’s easily extendable and you don’t need to remember the actual command that would be executed on the command line. You can’t forget what you configured :)

The following snippet defines a simple process file that allows you to restart your hapi app without downtime.

app.json

{
  "apps" : [{
    "name"            : "fs-platform",
    "script"          : "server.js",
    "instances"       : 2,
    "exec_mode"       : "cluster",
    "listen_timeout"  : 8000
  }]
}

The app.json includes the necessary configuration to run 2 instances in cluster mode of your application that gets kicked off with the server.js entry point. Running more than a single application instance will always result in PM2’s cluster mode.

Up to this point, you’ve prepared your hapi app for zero-downtime restarts with the hapi-graceful-pm2 plugin. Further, the PM2 process file defines two instances in cluster mode. Alright, you’re good to go.

Use the pm2 command line tool and start the app.json.

$ pm2 start pm2.json --env dev
[PM2][WARN] Applications fs-platform not running, starting...
[PM2] App [fs-platform] launched (2 instances)
┌─────────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐
│ App name    │ id │ mode    │ pid   │ status │ restart │ uptime │ cpu │ mem       │ watching │
├─────────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────┼───────────┼──────────┤
│ fs-platform │ 0  │ cluster │ 15394 │ online │ 0       │ 0s     │ 50% │ 32.9 MB   │ disabled │
│ fs-platform │ 1  │ cluster │ 15395 │ online │ 0       │ 0s     │ 40% │ 23.8 MB   │ disabled │
└─────────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

The code snippet above illustrates the command line output of PM2’s start procedure. You can immediately spot the two instances of your application that run in cluster mode. That’s exactly what you wanted the outcome to be. You can now access your application within the browser via domain or IP address or whatever your setup looks like.

Graceful Restarts with Zero Downtime

Within the previous steps of this guide, you’ve prepared your hapi application to run in cluster mode with PM2 and already started two processes. Assuming that you’ve added new features to your application, you want to deploy them and therefore need to restart your instances.

Actually, what you want is a graceful restart without downtime.

Pull the updates for your application and ultimately use PM2’s reload command instead of restart. With reload, PM2 will restart your processes one after another and wait until at least a single instance is ready to handle requests before initiating the next restart.

$ pm2 reload fs-platform
Reloads are now immutable, to update environment or conf use --update-env  
[PM2] Applying action reloadProcessId on app [fs-platform](ids: 0,1)
[PM2] [fs-platform](0) ✓
[PM2] [fs-platform](1) ✓
┌─────────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────┬────────────┬──────────┐
│ App name    │ id │ mode    │ pid   │ status │ restart │ uptime │ cpu │ mem        │ watching │
├─────────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────┼────────────┼──────────┤
│ fs-platform │ 0  │ cluster │ 17485 │ online │ 1       │ 2s     │ 78% │ 121.0 MB   │ disabled │
│ fs-platform │ 1  │ cluster │ 17486 │ online │ 1       │ 2s     │ 85% │ 121.5 MB   │ disabled │
└─────────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────┴────────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

The reload procedure will take longer, because of the waiting time for each instance being up again. Be patient while all instances of your application get restarted. Users requesting your application won’t notice the reload process going on behind the curtain. They’ll notice the deployed update in case there are visual changes on your websites.

Awesome! You did it! From now on, you don’t need to worry about downtimes during deployments. \o/

The Curse and Blessing of Timeouts

Throughout this tutorial, you’ve seen multiple timeouts. At first, while preparing your hapi server with the hapi-graceful-pm2 plugin, you had the option to define a timeout interval that hapi waits at most before shutting down.

Then, within the PM2 process file app.json, you’ve seen a listen_timeout which is the interval PM2 waits for a listen signal that indicates your server is back up „listening“ for connections. If you exceed the listen_timeout, PM2 will restart your process the hard way to get it back up.

We didn’t show you within this tutorial, but there’s an equivalent environment variable to listen_timeout called PM2_GRACEFUL_LISTEN_TIMEOUT. If you used the environment variable before and want to switch to the definition within the process file, make sure to clean up properly so you don’t get caught into strange behavior due to different values for listen_timeout and PM2_GRACEFUL_LISTEN_TIMEOUT.

The curse of all the timeouts is that you need to keep them either in sync or at least set the timeout for the hapi-graceful-pm2 plugin to a greater or equal value compared to the listen_timeout. Because both timeouts are used by another process and they shouldn’t interfere each other.

The hapi-graceful-pm2 timeout is used by hapi itself to wait at most the defined timeout before shutting down the hard way. The listen_timeout is used by PM2 to wait at most the defined time within that your hapi server should listen for connections again.

Outlook

Zero-downtime deployments are an essential part of your deployment pipeline because you skip all concerns that affect active users on your page. With the help of PM2, you can easily deploy your hapi application and gracefully restart the related processes.

Prepare your hapi server with the hapi-graceful-pm2 plugin to shut down your server correctly. Using PM2’s reload command sends a signal to stop your server (which closes existing connections) and also restarts your server processes sequentially. And the combination of your correct shutdown and the sequential restart results in always having a hapi instance available for client requests.

This extensive guide may arise various questions. Please use the comments below or shoot us a tweet @futurestud_io if you want to know more details about zero downtime deployments in hapi using PM2.

Make it rock & enjoy coding!

Explore the Library

Find interesting tutorials and solutions for your problems.