Topic 19 of 55
Process Management & PM2
Overview
Node.js is single-threaded — to use all CPU cores, you run multiple processes with the cluster module or PM2. Process managers also handle auto-restart on crash, log management, and zero-downtime reloads.
Syntax
javascript
import cluster from "cluster";
import os from "os";
if (cluster.isPrimary) {
const numCPUs = os.cpus().length;
console.log("Starting " + numCPUs + " workers");
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on("exit", (worker, code, signal) => {
console.log("Worker", worker.process.pid, "died. Restarting...");
cluster.fork();
});
} else {
app.listen(3000);
console.log("Worker", process.pid, "listening on :3000");
}
// pm2.config.js
module.exports = {
apps: [{
name: "api-server",
script: "dist/index.js",
instances: "max",
exec_mode: "cluster",
watch: false,
max_memory_restart: "500M",
}]
};Common Pitfalls
- process.exit(0) immediately kills the process — in-flight requests are dropped. Use graceful shutdown to finish them first.
- Cluster workers cannot share in-memory state — use Redis or a database for shared state in clustered apps.
- Interview tip: PM2 cluster mode + pm2 reload does zero-downtime deployment — it replaces workers one at a time.
Real-World Example
Graceful shutdown on SIGTERM for zero-downtime deployments
example
javascript
import { createServer } from "http";
const server = createServer(app);
const connections = new Set();
server.on("connection", (conn) => {
connections.add(conn);
conn.on("close", () => connections.delete(conn));
});
async function gracefulShutdown(signal) {
console.log(signal + " received. Starting graceful shutdown...");
server.close(async () => {
console.log("HTTP server closed");
await pool.end();
await redis.quit();
process.exit(0);
});
// Force close after 30s
setTimeout(() => {
console.error("Forced shutdown after timeout");
connections.forEach(conn => conn.destroy());
process.exit(1);
}, 30000);
}
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
process.on("SIGINT", () => gracefulShutdown("SIGINT"));