Process management refers to various activities around the creation, termination, and monitoring of processes. A process manager is a program that ensures that your applications always stay online after being launched.
Process managers can prevent downtime in production by automatically restarting your application after a crash or even after the host machine reboots. They are also useful in development: they auto-restart an app once its source files or dependencies are updated. Process managers also typically provide monitoring tools that access application logs and other key metrics, such as CPU and memory usage.
PM2 is a Node.js process manager that comes with a built-in load balancer. It helps facilitate production deployments and enables you to keep running applications alive indefinitely (even when accidents occur). It also lets you gain insights into your application's runtime performance and resource consumption and scale your application in real-time through its clustering feature.
In this article, we'll examine PM2's most important features and discover how it can help you increase the resilience of your Node.js applications in production.
Getting Started with PM2
PM2 is available as an NPM package, so you
can install it through npm
or yarn
:
After installing PM2, run npx pm2 --version
to see the installed version:
If you don't want to prefix the pm2
command with npm
every time, you can
install it globally:
Aside from the main pm2
command, the
installation provides some other executables:
pm2-dev
: a development tool for restarting your application when file changes in the directory are detected (similar to Nodemon).pm2-runtime
: designed to be a drop-in replacement for thenode
binary in Docker containers. It helps keep the running application in the foreground (unlikepm2
, which sends it to the background) so that the container keeps running.pm2-docker
: an alias forpm2-runtime
.
Start Your Node.js App in Development Mode with PM2
It can be quite tedious to restart your application server in development every
time you change the source files. Using the pm2-dev
binary to start
your application can take care of that concern automatically:
At this point, your server will auto-restart each time you create, modify or
delete a source file in your project. It also works when you add or
remove a dependency with npm
or yarn
.
Start Your Node.js App in Production Mode with PM2
When deploying an application to production, you can use the pm2
binary to
start it in the background. It launches a daemon that monitors your application
and keeps it running indefinitely.
PM2 defaults to the name of the entry file as the app's name
, but you can
use a more recognizable name through the --name
option. This name is what
you'll use to reference the application in many pm2
subcommands.
Suppose you need to ensure that your application has established connections with
other services (such as the database or cache) before being considered
"online" by PM2. In that case, you can use the --wait-ready
option when starting your
application. This causes PM2 to wait for 3 seconds (by default) or for a ready event
(process.send('ready')
) before the application is considered ready. You can
use the --listen-timeout
option to change the length of the delay.
Monitoring Your Running Applications in PM2
To list your running applications, use the pm2 list
command. This prints a
table describing the state of all running applications with columns for:
- the app name and id
- CPU and memory usage
- number of restarts (
↺
) - uptime
- process id
- the mode (
fork
orcluster
)
and others.
You can use this table alongside a host monitoring service like AppSignal to give you a complete picture of your application and its host environment:
If you see only a subset of this information, try enlarging your terminal
window. The list
subcommand will not display all the columns if your terminal
window is too small. You can also sort the output table according to a metric of
your choice:
If you require more information about a particular app beyond what list
provides, use the show
subcommand and pass the app name to view more
detailed application process metadata. Some of the metrics and data
presented in the output include the app's:
- output and error log files
- heap size and usage
- event loop latency
- uptime
- number of restarts
- source control metadata
and more.
Another way to keep tabs on your running applications is through the built-in
terminal dashboard (accessed through the monit
subcommand). This allows
you to view live data on resource usage and logs for each of your applications.
Restarting Your Node.js Application with PM2
PM2 allows you to configure several different strategies for how your
Node.js application should restart. By default, it restarts your application if it exits
or crashes to minimize the impact to your customers in production while the
source of the crash is investigated. The restart
subcommand is also
available for manually restarting your application at any time.
To ensure a graceful shutdown, make sure you intercept the SIGINT
signal to
stop all new requests and finish up existing ones before allowing your program
to exit.
You can use the --kill-timeout
option to ensure that a graceful shutdown does
not take too long:
Auto Restart Based on Memory Usage
The --max-memory-restart
option is available to restart an app when it
reaches a certain memory threshold. This can help prevent a Node.js heap out of
memory error. You can specify the memory limit in kilobytes
(K
), Megabytes (M
), or Gigabytes (G
).
Auto Restart Based on Cron Schedule
PM2 also offers a restart strategy based on the Cron syntax. This allows you to schedule a restart at a specific time each day / on certain days of the week / a set time interval (such as every 48 hours).
Auto Restart on File Change
Remember how pm2-dev
auto-restarts your application when you make changes to a file? You can
configure the pm2
command to act in a similar manner through the --watch
subcommand. In the table outputted by pm2 list
, look at the watching
column to observe the watch
status of an application.
Auto Restart after a Delay
You can configure the --restart-delay
option to set a delay for automatic
restarts. The delay should be supplied in milliseconds.
Ignore Some Exit Codes When Auto Restarting
PM2 auto-restarts your app when the process exits, but it does not take the exit
code into account by default, so it
restarts regardless of whether the app exits cleanly or crashes. If this
behavior is not desired, you can use the --stop-exit-codes
option to set exit
codes that should not prompt PM2 to auto-restart. For example, you can ensure
PM2 does not auto-restart on a clean exit with the following command:
Restarting Processes after a System Reboot
The previous section covered a variety of ways to restart your application after it is launched. However, none of the strategies there will keep your application up if your server reboots. Notably, PM2 ships with a startup feature that can help solve this problem. You can combine this with a good uptime monitoring service like AppSignal's to guarantee that your application comes back online quickly, even if an accident happens.
You'll need to generate a startup script for your server's init system to execute on system boot and launch the PM2 process, which will
subsequently start the configured application processes immediately. You can
allow PM2 to autodetect your startup script or pass the init system used by
your operating system, which could be systemd
, upstart
, launchd
, rcd
, or
systemv
.
You should receive the following output:
You'll need to copy and paste the generated command into the terminal, and then run it as the root:
If everything goes well, you'll see the following output, indicating that PM2 is configured to start at boot.
At this point, you can run pm2 save
to save your process list. This saves the
processes currently managed by PM2 to disk so they're accessible to the
daemon on system boot.
Go ahead and restart your computer or server. Once it boots back up, run
pm2 list
to see if all the processes are restored. If PM2 doesn't restore
them automatically, you can manually relaunch them with the resurrect
subcommand. You then won't need to start each process individually.
At any point in the future, you can run pm2 save
again to update the list of
processes that should be restored on boot or when using the resurrect
subcommand.
Clustering with PM2
Clustering in Node.js refers to creating child processes that run simultaneously and share the same port in an application. This technique makes it possible to horizontally scale a Node.js application on a single machine, taking advantage of the processing capabilities offered by multi-core systems (since an instance of a Node.js app only runs on a single thread).
The standard Node.js library provides a cluster module to set up clustering in Node.js applications. In a nutshell, it creates child processes (workers) and distributes incoming connections across the simultaneously running worker processes. You'll need to modify your source code to spawn and manage the workers and set up how you'd like to distribute incoming connections amongst them.
PM2 also provides a cluster mode that uses the native cluster module under the
hood. However, it does not require any modifications to the application's source
code. Instead, all you need to do to start a Node.js program in cluster mode is
to supply the -i
option to the start
subcommand, as follows:
The -i
or instances option above allows you to specify the number of workers
(child processes) that PM2 should launch. You can set 0
or max
to specify that PM2 should spawn as many workers as the number of available CPU
cores (as above). Alternatively, you can set the exact number of workers to be
greater than the number of available CPU cores, if desired. If you want to add
additional worker processes on the fly, use the scale
subcommand as shown
below:
Once your application launches in cluster mode, incoming requests to the
server will be automatically load-balanced across all the worker processes, which
can significantly improve throughput. This feature also enables you to restart
your app in production (using pm2 restart
) without suffering any downtime
since PM2 waits for the new workers to become operational before it kills the
old ones.
PM2's clustering feature works best when your application is completely stateless. You won't need any code modifications to scale on the same server or even across multiple servers if your app doesn't maintain any state in individual processes. If your application isn't stateless, you'll likely get better results directly using the native cluster module.
Log Management in PM2
Log management is quite straightforward in PM2. The logs for all your running
applications are placed in the ~/.pm2/logs
directory, and they can be
displayed with the logs
subcommand. All log entries are prefixed with the application's name to ensure easy identification.
You can also clear log data with the flush
subcommand:
To enable log rotation, install the following module:
Wrap Up and Next Steps: Dive Further into PM2
I hope this article has helped to crystallize the importance of process management in Node.js applications and how to leverage PM2's robust feature set to manage your application efficiently.
PM2 offers other capabilities that were not covered in this article such as Docker integration, a JavaScript API, and a daemon-less mode, so ensure you check out PM2's documentation to learn more about these advanced features.
Thanks for reading, and happy coding!
P.S. If you liked this post, subscribe to our JavaScript Sorcery list for a monthly deep dive into more magical JavaScript tips and tricks.
P.P.S. If you need an APM for your Node.js app, go and check out the AppSignal APM for Node.js.