How JavaScript works: introduction to PM2, Strongloop, and Forever + 4 tips for Production Process Managers
This is post # 45 of the series, dedicated to exploring JavaScript and its building components. In the process of identifying and describing the core elements, we also share some rules of thumb we use when building SessionStack, a JavaScript tool for developers to identify, visualize, and reproduce web app bugs through pixel-perfect session replay.
The goal of every organization that builds software is to provide scalable products that deliver value to their customers. This means that the software has to be closely monitored so that the program runs smoothly and there’s no downtime. However, what happens when the software crashes during scaling or how developers can monitor their applications to ensure the guaranteed uptime and functional quality?
This is where production process managers come in. They are tools that allow developers to keep their processes or scripts alive. With production process managers your application will restart when there’s a failure or a crash. Production managers also make it easier to monitor applications properly as they provide logs on the state of the application.
In this article, we will be exploring the different production process managers, why they are necessary, and how to use them in a Node.js-based applications.
What are Production Process Managers
Production process managers are tools that run the application’s process continuously and ensure that it is always alive. It works as a daemon and runs the application’s process in the background.
A daemon runs as a background process while executing multitasks, therefore it is not in the direct control of an interactive user. For instance, for programs that are in direct control of an interactive user, closing the program window can stop the program from running. However, for production process managers, the user cannot stop the program from running simply by closing the program window. To stop production process managers from running, the developer will run a command to stop a single application or all applications connected to the process manager.
While production process managers are excellent with multitasking, they also perform system administration tasks such as modifying the environment, editing configurations, restarting applications at failure, etc. all this without downtime.
Why do you need a Process Manager
Process managers are necessary, especially for Node.js-based applications.
Hot reload
Node.js applications will stop once there’s an error in a process. This will cause downtime if it’s not noticed earlier. Sometimes, when a dependency is downloaded in a Node.js application, there’s a need to reload the application. Production process managers reload an application whenever there’s a change. It also reloads the application automatically whenever there’s a failure or crash to ensure there’s no downtime.
Configurations
Production process managers allow developers to configure the behavior unique to an application. These behavioral configurations of the application make managing and monitoring the application easy. For instance, to investigate the cause of an error properly, developers can specify a delay before an automatic reload triggered by a failure or crash for each application.
Multitasking
Production process managers are not only suitable in the production environment, but they can also be used in the development environment. Most times, managing multiple Node.js applications can become too difficult to handle. Production process managers work in the background making it excellent in handling multiple applications simultaneously.
Monitoring and management
Production process managers not only provide logs as a means of application monitoring, but it also gives developers access to key metrics of the application like memory and CPU usage.
Setting up a Node.js application
Node.js is an open-source server-side runtime environment for JavaScript. It is cross-platform, i.e runs on various environments, and is a very popular JavaScript runtime environment. In this section, we will be setting up a Node.js application as well as integrating production process managers into the application we have created.
Firstly, you’ll have to install Node.js on your local machine if you don’t have it installed already. Restart your local machine and confirm that Node.js is properly installed.
node — version
Next, create a folder in your machine for the Node.js application, name the folder myapp
. In your terminal, navigate to myapp
with cd myapp
and execute npm init
. Provide the information necessary and a package.json
file will be created at the root of your project with the information you provided. Create a file in the root of your folder and name it index.js
. This is the entry point of your application. Put the code below into the index.js
file you just created:
Install express
by running the command below in your terminal:
npm i express
Now, run node index.js
to start your application. Navigate to http://localhost:3000/, and the page will display “This is Home Page.”.
Because our application isn’t connected to a production process manager, notice how the connection is lost if you shut down the terminal. Also, the application doesn’t affect recent changes made until you restart the application manually. Now, let’s connect the application we just created to production process managers.
Using Process Managers for a Node.js-based application
There are different production process managers for Node.js-based applications. Let’s explore the different process managers and how to use them.
PM2
PM2 is an advanced production process manager that can run on any script. This production process manager like other production process managers allows developers to keep their application alive forever and perform system administrative tasks without downtime. PM2 provides application management, load balancing, which allows multitasking, allowing developers to configure their applications to suit their needs.
To install PM2 in your Node.js application, run the command below in your terminal:
// Install with npmnpm install pm2 -g// Install with yarnyarn global add pm2
Notice how pm2 dependency has been added to your package.js
file. Now, instead of running node index.js
to start your application, run the command below to start your application with pm2:
pm2 start index.js
If we close the terminal, notice that our application is still running. Also, notice that the new changes you apply in your application are not reflected. This is because watching is disabled for the application. To turn on watching for the application, restart the application with watch
by running the command below:
pm2 restart index.js — watch
Cluster mode
Running an application in pm2 with the cluster mode allows networked Node.js applications (http(s)/tcp/udp server)
to scale across all CPUs available. Cluster mode increases the performance of an application depending on the number of CPUs available.
To run the application in cluster mode, execute the command below:
pm2 start index.js -i max
The -i
flag is the cluster option whereas max
instructs pm2 to detect the number of CPUs available and run as many as possible.
Persistent application -, what happens when your machine stops unexpectedly
The pm2 monit
command allows developers to monitor their processes. To look at our application’s dashboard so that we can monitor it properly, run the command below in your terminal.
pm2 monit
To stop the application from running, execute the command below in your terminal.
pm2 stop index.js
However, notice how the application is still displayed on the pm2 table:
To remove the application from the pm2 table, run the command below:
pm2 delete index.js
However, what happens if your machine shuts down unexpectedly, how do you avoid downtime?
When you generate a startup script, PM2 will automatically restart at boot time. PM2 automatically generates and configures a startup script when you execute the pm2 startup
command. To use the startup script, make sure your system has a supported init
system. Here’s a list of the supported init systems:
The init systems are automatically detected by PM2 when you run the pm2 startup
command. If you attempt to run the startup script without the init system, you’ll get an error:
Although PM2 has no built-in startup support for Windows, pm2-installer tends to fill in the void, allowing developers to use the startup command.
Configuration file
When managing multiple applications, it becomes difficult to pass configurations in the terminal. PM2 allows you to generate a simple JavaScript configuration file to manage and organize configurations.
To create a configuration file, run the command below:
pm2 init simple
This command will generate an ecosystem.config.js
file at the root of your project. With the configuration file, you can start only one application by passing its name and the only
flag:
pm2 start ecosystem.config.js — only index.js
Also, it is in the configuration file that the developer specifies the development and production variables:
This allows you to decide which environment you want to run by passing the name of the environment. For instance, if you want to run in the production environment, you’ll execute the command below:
pm2 start ecosystem.config.js — env production
Static serving and deployment with PM2
PM2 has a powerful deployment system that allows easy upgrading of applications in the production environment. First, you’ll add a deploy attribute to the ecosystem.config.js file
. Here’s a simple deployment configuration.
Next, install PM2 in your remote server and provision the server. To provision the server, run the command below:
pm2 deploy production setup
After provisioning the server, run the command below to deploy your application:
pm2 deploy production
Also, while using PM2 in your local environment, you can host static files easily over http
with the serve command.:
pm2 serve <path> <port>
If you don’t specify a path
or port
, the current folder will be used as the path while the default port 8080
will be used as port
.
StrongLoop process manager
Strongloop process manager is another production process manager like PM2. However, strongloop process manager is a Node.js based process manager and can run only on Node.js based applications. While the strongloop process manager looks similar to PM2, they are different. For instance, PM2 allows the use of NGINX as a HTTP proxy for serving static files rapidly but the strongloop process manager does not. Let’s explore the strongloop process manager and its features.
Strongloop process manager can be connected to an application in your local machine or a remote environment.
Strongloop for remote use
You can install strongloop for use in a production environment using npm
or with docker
. To install strongloop with npm
, run the command below:
npm install -g strong-pm
For Linux distributed systems that support upstart
or systemd
, it is better to install process managers as a service so that it can start when the system boots to aggregate logs properly, etc. To install strongloop as a service, run the command below:
Or, install strongloop with docker using the command below:
sudo sl-pm-install — driver docker
When you set up strongloop process manager to “Dockerize” apps deployed to it, your app will be turned into a Docker image and then run in a Docker container. If you don’t want to install anything, you can run PM2 from the docker hub. Run the command below to download the image, start a strongloop process manager container and create an upstart
or systemd
config file:
curl -sSL https://strong-pm.io/docker.sh | sudo /bin/sh
Next, build your application with slc build
, then run the command below to deploy your application:
slc deploy http://your.remote.host
Now that you’ve deployed your application, you can check the status of your application by running the command below:
slc ctl status — control http://your.remote.host
Just like in PM2, the strongloop process manager allows you to change the cluster size on the remote host. By default, the strongloop process manager runs one process per CPU. However, you can choose to change the cluster size to suit your needs. For instance, you can change the cluster size of your remote host to two with the command below:
slc ctl — control http://your.remote.host set-size <app name> 2
When there are changes to your application’s source code, you can re-deploy your application by building your application and deploying it to the production host with the deploy command. This way, the strongloop process manager automatically performs a rolling restart of all processes, so you get zero downtime.
Strongloop for local use
Strongloop process manager can also be used in a local machine to monitor and keep your application alive. First, install strongloop into your local environment with the command below:
npm install -g strongloop
Next, start your application with slc start
:
You can check the status of your application with the command below to confirm that it started successfully:
slc ctl status <app name>
Also, you can check the logs of your application with the log-dump
command:
slc ctl log-dump <app name>
Forever
Forever is a command-line interface tool that keeps Node.js scripts running forever. Just like other process managers, forever runs Node.js scripts in the background as a daemon. Forever, just like PM2 can run other scripts that are not Node.js based. While Forever is a CLI tool, developers can choose to use this tool programmatically without the CLI by installing the forever-monitor.
Forever CLI
To install the forever tool and use the CLI, run the command below in your terminal:
npm install forever -g
Now, you can start your application with the command below:
forever start index.js
Just like other production process managers, you can create a config
file and write app-specific configurations into the config file
. For example, consider an application with a file structure below:
│└── development.json└── package.json└── index.js
You can write app-specific configurations into the development.json
file as shown below:
You can start this application by running the command below in your terminal:
forever start ./forever/development.json
Using Forever programmatically
With the Forever monitor, you can use forever from inside your code like other dependencies. First, install forever-monitor via npm with the command below.
npm install forever-monitor
Next, declare the dependency in your application like you would declare other dependencies:
var forever = require(‘forever-monitor’);
Now, you can create multiple processes to monitor your applications:
Below is a list of frequently used commands in Forever and their descriptions:
Tips for using production process managers
Production process managers are usually fast and robust, they allow you to manage your application efficiently. While we have explored how to use production process managers in a local machine, let’s look at the best practices for using production process managers in a production environment:
- Keep development and production as similar as possible. This is because a large change in production can break your application.
- Store configurations for the environment in the
ecosystem.config.js
file so that configurations that are meant for the development environment are not mixed with configurations for the production environment. - Run admin/management tasks as one-off processes so that you don’t keep restarting your application. Only restart your application when necessary.
- Explicitly declare and isolate dependencies. For instance, you should turn off watching in your
node-modules
folder since it contains dependencies.
pm2 start env.js — watch — ignore-watch=”node_modules”
Conclusion
As an application’s server throws an error, it malfunctions and can cause downtime if not managed properly. With production process managers, developers monitor their applications as well as get key metrics about their apps.
Although some tools like nodemon can restart a Node.js application whenever a change in the file is noticed, they don’t offer restart on failure or other features a production process manager offers like multitasking and running in the background, etc.
The production process managers we have discussed in this article are the popular production process managers used in Node.js-based applications. Some of the other production process managers that can be used in Node.js based applications are supervisor and systemD.
Production process managers makes it much easier for products like SessionStack to be available as a service in the cloud with continuous availability. SessionStack collects behavioral data during customer journeys, allowing you to replay them as a video. Since SessionStack collects a large amount of behavioral data concurrently, production process managers are an important aspect of our stack that allows us to deliver a reliable and robust service.
There is a free trial if you’d like to give SessionStack a try.
If you missed the previous chapters of the series, you can find them here:
- An overview of the engine, the runtime, and the call stack
- Inside Google’s V8 engine + 5 tips on how to write optimized code
- Memory management + how to handle 4 common memory leaks
- The event loop and the rise of Async programming + 5 ways to better coding with async/await
- Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path
- A comparison with WebAssembly + why in certain cases it’s better to use it over JavaScript
- The building blocks of Web Workers + 5 cases when you should use them
- Service Workers, their life-cycle, and use case
- The mechanics of Web Push Notifications
- Tracking changes in the DOM using MutationObserver
- The rendering engine and tips to optimize its performance
- Inside the Networking Layer + How to Optimize Its Performance and Security
- Under the hood of CSS and JS animations + how to optimize their performance
- Parsing, Abstract Syntax Trees (ASTs) + 5 tips on how to minimize parse time
- The internals of classes and inheritance + transpiling in Babel and TypeScript
- Storage engines + how to choose the proper storage API
- The internals of Shadow DOM + how to build self-contained components
- WebRTC and the mechanics of peer to peer connectivity
- Under the hood of custom elements + Best practices on building reusable components
- Exceptions + best practices for synchronous and asynchronous code
- 5 types of XSS attacks + tips on preventing them
- CSRF attacks + 7 mitigation strategies
- Iterators + tips on gaining advanced control over generators
- Cryptography + how to deal with man-in-the-middle (MITM) attacks
- Functional style and how it compares to other approaches
- Three types of polymorphism
- Regular expressions (RegExp)
- Introduction to Deno
- Creational, Structural, and Behavioural design patterns + 4 best practices
- Modularity and reusability with MVC
- Cross-browser testing + tips for prerelease browsers
- The “this” variable and the execution context
- High-performing code + 8 optimization tips
- Debugging overview + 4 tips for async code
- Deep dive into call, apply, and bind
- The evolution of graphics
- Dockerizing a Node.js application
- A deep dive into decorators
- Best practices for data compliance
- Proxy and Reflect
- SVG and its use cases (part 1)
- Class static blocks + 6 proposed semantics
- Introduction to Graphs and Trees