Do not wait; the time will never be “just right.” Start where you stand, and work with whatever tools you may have at your command, and better tools will be found as you go along.
—George Herbert
Working with processes
Monitoring logs
Monitoring resource usage
Advanced process management
Load balancing across multiple processors
Zero downtime deployments
Installation
Installing the pm2 Command-Line Utility via npm
Note
Node’s package manager (npm) allows users to install packages in one of two contexts: locally or globally. In this example, pm2 is installed within the global context, which is typically reserved for command-line utilities.
Working with Processes
Simple Express Application
Summary of Columns Shown in Figure 3-1
Heading | Description |
---|---|
App name | The name of the process. Defaults to the name of the script that was executed. |
id | A unique ID assigned to the process by PM2. Processes can be referenced by name or ID. |
mode | The method of execution (fork or cluster). Defaults to fork. Explored in more detail later in the chapter. |
pid | A unique number assigned by the operating system to the process. |
status | The current status of the process (e.g., online, stopped, etc.). |
restart | The number of times the process has been restarted by PM2. |
uptime | The length of time the process has been running since last being restarted. |
memory | The amount of memory consumed by the process. |
watching | Indicates whether PM2 will automatically restart the process when it detects changes within a project’s file structure. Particularly useful during development. Defaults to disabled. |
Note
Figure 3-2 assumes the existence of the curl command-line utility within your environment. If you happen to be working in an environment where this utility is not available, you could also verify the status of this application by opening it directly within your web browser.
Frequently Used Commands for Interacting with PM2 Processes
Command | Description |
---|---|
list | Displays an up-to-date version of the table shown in Listing 3-4 |
stop | Stops the process, without removing it from PM2’s list |
restart | Restarts the process |
delete | Stops the process and removes it from PM2’s list |
show | Displays details regarding the specified process |
Recovering from Errors
At this point, you are now familiar with some of the basic steps involved in interacting with PM2. You’ve learned how to create new processes with the help of PM2’s start command. You’ve also discovered how you can subsequently manage running processes with the help of commands such as list, stop, restart, delete, and show. We’ve yet to discuss, however, much of the real value that PM2 brings to the table in regard to managing Node processes. We’ll begin that discussion by discovering how PM2 can assist Node applications in automatically recovering from fatal errors.
Modified Version of Our Original Application That Throws an Uncaught Exception Every 4 Seconds
Such behavior won’t get us very far in a real usage scenario. Ideally, an application that has been released to a production environment should be thoroughly tested and devoid from such uncaught exceptions. However, in the event of such a crash, an application should at the very least be able to bring itself back online without requiring manual intervention. PM2 can help us accomplish this goal.
Notice anything interesting here? Based on the values within the status, restart, and uptime columns, we can see that our application has crashed three times already. Each time, PM2 has helpfully stepped in and restarted it for us. The most recent process has been running for a total of 2 seconds, which means we can expect another crash (and automatic restart) 2 seconds from now.
PM2’s ability to assist applications in recovering from fatal errors in a production environment, while useful, is just one of several useful features the utility provides. PM2 is also equally useful within development environments, as we’ll soon see.
Responding to File Changes
Imagine a scenario in which you’ve recently begun work on a new Node project. Let’s assume it’s a web API built with Express. Without the help of additional tools, you must manually restart the related Node process in order to see the effects of your ongoing work—a frustrating chore that quickly grows old. PM2 can assist you in this situation by automatically monitoring the file structure of your project. As changes are detected, PM2 can automatically restart your application for you, if you instruct it to do so.
As changes are saved to this project’s files, subsequent calls to PM2’s list command will indicate how many times PM2 has restarted the application, as seen in a previous example.
Monitoring Logs
We recently explored how to allow PM2 to manage the execution of this application for us via the start command (see Figure 3-1). Doing so provides us with several benefits, but it also causes us to lose immediate insight into the output being generated by our application to the console. Fortunately, PM2 provides us with a simple mechanism for monitoring such output.
Arguments Accepted by PM2’s logs Command
Argument | Description |
---|---|
–raw | Displays the raw content of log files, stripping prefixed process identifiers in the process |
–lines <N> | Instructs PM2 to display the last N lines, instead of the default of 20 |
Monitoring Resource Usage
In the previous section, you learned how PM2 can assist you in monitoring the standard output and errors being generated by processes under its control. In much the same way, PM2 also provides easy-to-use tools for monitoring the health of those processes, as well as for monitoring the overall health of the server on which they are running.
Monitoring Local Resources
Monitoring Remote Resources
The information provided by PM2’s monit command provides us with a quick and easy method for monitoring the health of its processes. This functionality is particularly helpful during development, when our primary focus is on the resources being consumed within our own environment. It’s less helpful, however, as an application moves into a remote, production environment that could easily consist of multiple servers, each running its own instance of PM2.
In this example, we enable PM2’s web-accessible JSON API by calling the utility’s web command. PM2 implements this functionality as part of a separate application that runs independently of PM2 itself. As a result, we can see that a new process, pm2-http-interface, is now under PM2’s control. Should we ever wish to disable PM2’s JSON API, we can do so by removing this process as we would any other, by passing its name (or ID) to the delete (or stop) commands.
Excerpt of the Information Provided by PM2’s JSON API
Advanced Process Management
Most of this chapter’s focus so far has revolved around interactions with PM2 that occur primarily via the command line. On their own, commands such as start, stop, restart, and delete provide us with simple mechanisms for managing processes in a quick, one-off fashion. But what about more complex scenarios? Perhaps an application requires that additional parameters be specified at runtime, or perhaps it expects that one or more environment variables be set.
JSON Application Declarations
Sample of the Various Options Available Within a JSON Application Configuration File
Descriptions of the Various Configuration Settings Shown in Listing 3-5
Setting | Description |
---|---|
name | Name of the application. |
cwd | Directory from which the application will be launched. |
args | Command-line arguments to be passed to the application. |
script | Path to the script with which PM2 will launch the application (relative to cwd). |
node_args | Command-line arguments to be passed to the node executable. |
log_date_format | Format with which log timestamps will be generated. |
error_file | Path to which standard error messages will be logged. |
out_file | Path to which standout output messages will be logged. |
pid_file | Path to which the application’s PID (process identifier) will be logged. |
instances | The number of instances of the application to launch. Discussed in further detail in the next section. |
max_restarts | The maximum number of times PM2 will attempt to restart (consecutively) a failed application before giving up. |
max_memory_restart | PM2 will automatically restart the application if the amount of memory it consumes crosses this threshold. |
cron_restart | PM2 will automatically restart the application on a specified schedule. |
watch | Whether or not PM2 should automatically restart the application as changes to its file structure are detected. Defaults to false. |
ignore_watch | An array of locations for which PM2 should ignore file changes, if watching is enabled. |
merge_logs | If multiple instances of a single application are created, PM2 should use a single output and error log file for all of them. |
exec_mode | Method of execution. Defaults to fork. Discussed in further detail in the next section. |
autorestart | Automatically restarts a crashed or exited application. Defaults to true. |
vizon | If enabled, PM2 will attempt to read metadata from the application’s version control files, if they exist. Defaults to true. |
env | Object containing environment variable keys/values to pass to the application. |
Source Code for the main and weather Applications
JSON Application Configuration File for This Chapter’s microservices Project microservices/pm2/development.json
The application configuration file shown here provides PM2 with instructions on how to launch each of the applications included within this project. In this example, PM2 is instructed to restart each application if changes are detected to either’s file structure, or if they begin to consume more than 60MB of memory. The file also provides PM2 with separate environment variables to be passed to each process.
Note
Before running this example, you will need to adjust the values for the cwd settings within this file so that they reference the absolute path to the microservices folder on your computer. After making the appropriate adjustments, launch both applications with a single call to PM2, as shown in Figure 3-12.
Load Balancing Across Multiple Processors
The single-threaded, nonblocking nature of Node’s I/O model makes it possible for developers to create applications capable of handling thousands of concurrent connections with relative ease. While impressive, the efficiency with which Node is capable of processing incoming requests comes with one major expense: an inability to spread computation across multiple CPUs. Thankfully, Node’s core cluster module provides a method for addressing this limitation. With it, developers can write applications capable of creating their own child processes—each running on a separate processor, and each capable of sharing the use of ports with other child processes and the parent process that launched it.
Before we close out this chapter, let’s take a look at a convenient abstraction of Node’s cluster module that is provided by PM2. With this functionality, applications that were not originally written to take advantage of Node’s cluster module can be launched in a way that allows them to take full advantage of multiprocessor environments. As a result, developers can quickly scale up their applications to meet increasing demand without immediately being forced to bring additional servers to bear.
Express Application to Be Scaled Across Multiple CPUs
JSON Application Configuration File with Which Our Application Will Be Launched
The application configuration file shown in Listing 3-9 contains two key items of interest. The first is the instances property . In this example, we specify a value of 0, which instructs PM2 to launch a separate process for every CPU that it finds. The second is the exec_mode property. By specifying a value of cluster, we instruct PM2 to launch its own parent process, which will in turn launch separate child processes for our application with the help of Node’s cluster module.
Note
When launching applications in cluster mode, PM2 will print a message to the console warning that this functionality is still a beta feature. According to the lead developer of PM2, however, this functionality is stable enough for production environments, so long as Node v0.12.0 or higher is being used.
Before you continue, you can quickly remove each of the eight processes launched by this example by running $ pm2 delete multicore.
Zero Downtime Deployments
After launching an application in cluster mode, PM2 will begin forwarding incoming requests in a round-robin fashion to each of the eight processes under its control—providing us with an enormous increase in performance. As an added benefit, having our application distributed across multiple processors also allows us to release updates without incurring any downtime, as we will see in a moment.
Copying the updated source code to the appropriate server(s)
Restarting each of the processes under PM2’s control
As these steps take place, a brief period of downtime will be introduced, during which incoming requests to the application will be rejected—unless special precautions are taken. Fortunately, launching applications with PM2 in cluster mode provides us with the tools we need to take those precautions.
Application Designed to Take Advantage of PM2’s gracefulReload Command
Previous examples have demonstrated the use of PM2’s restart command, which immediately stops and starts a specified process. While this behavior is typically not a problem within nonproduction environments, issues begin to surface when we consider the impact it would have on any active requests that our application may be processing at the moment this command is issued. When stability is of the utmost importance, PM2’s gracefulReload command serves as a more appropriate alternative.
When called, gracefulReload first sends a shutdown message to each of the processes under its control, providing them with the opportunity to take any necessary precautions to ensure that any active connections are not disturbed. Only after a configurable period of time has passed (specified via the PM2_GRACEFUL_TIMEOUT environment variable) will PM2 then move forward with restarting the process.
In this example, after receiving the shutdown message, our application responds by calling the close() method on the HTTP server that was created for us by Express. This method instructs our server to stop accepting new connections, but allows those that have already been established to complete. Only after 10 seconds have passed (as specified via PM2_GRACEFUL_TIMEOUT) will PM2 restart the process, at which point any connections managed by this process should already have been completed.
Summary
PM2 provides developers with a powerful utility for managing Node applications that is equally at home in both production and nonproduction environments. Simple aspects, such as the utility’s ability to automatically restart processes under its control as source code changes occur, serve as convenient timesavers during development. More advanced features, such as the ability to load balance applications across multiple processors and to gracefully restart those applications in a way that does not negatively impact users, also provide critical functionality for using Node in a significant capacity.
Related Resources
PM2 Home: http://pm2.keymetrics.io/