process-management
Process Management — PM2
All applications MUST run through PM2. Direct invocations (node, bun, python) are forbidden for any process that produces output or has a lifecycle.
Installation (First Time Only)
Check if PM2 is installed:
pm2 --version
If command not found, install globally:
npm install -g pm2
Verify installation:
pm2 --version # should print version number
pm2 ping # should respond "pong"
Pre-Start Check (MANDATORY)
Before starting any process, check what is already running:
pm2 jlist
online→ already running, usepm2 logs <name>to observestopped→ usepm2 restart <name>- Not in list → proceed to start
Never start a duplicate process. Always check first.
Start a Process
# CLI (quick)
pm2 start app.js --name myapp --watch --no-autorestart
# With interpreter
pm2 start script.py --interpreter python3 --name worker --watch --no-autorestart
# From ecosystem config (preferred for reproducibility)
pm2 start ecosystem.config.cjs
Ecosystem Config (Standard Template)
autorestart: false — process stops on crash, no automatic recovery
watch: true — restarts on file changes in watched directories only
// ecosystem.config.cjs
module.exports = {
apps: [{
name: "myapp",
script: "src/index.js",
watch: ["src", "config"],
watch_delay: 1000,
autorestart: false,
ignore_watch: [
"node_modules",
".git",
"logs",
"*.log",
".pm2",
"public",
"uploads"
],
watch_options: {
followSymlinks: false,
usePolling: false
},
log_date_format: "YYYY-MM-DD HH:mm:ss",
out_file: "./logs/out.log",
error_file: "./logs/error.log"
}]
};
Log Viewing
pm2 logs <name> # stream live (Ctrl+C to stop)
pm2 logs <name> --lines 100 # last 100 lines then stream
pm2 logs <name> --err # errors only
pm2 logs <name> --out # stdout only
pm2 logs <name> --nostream --lines 200 # dump without follow
pm2 logs --json # structured JSON output
pm2 flush # clear all log files
Log files: ~/.pm2/logs/<name>-out.log / <name>-error.log
Windows path: C:\Users\<user>\.pm2\logs\
Lifecycle Management
pm2 list # view all processes and status
pm2 jlist # JSON output for scripting
pm2 info <name> # detailed process info
pm2 stop <name> # stop (keeps in list)
pm2 restart <name> # restart
pm2 delete <name> # stop + remove from list
pm2 delete all # remove all processes
pm2 ping # check if PM2 daemon is alive
When work is complete: always pm2 delete <name> to clean up orphaned processes.
Stopping a watched process: pm2 stop while watch is active restarts on next file change.
To fully halt: pm2 delete <name> (removes it entirely).
Windows vs Linux
File Watching
| Environment | Config |
|---|---|
| Linux native | usePolling: false (inotify kernel events) |
WSL watching /mnt/c/... |
usePolling: true, interval: 1000 |
| Windows native | usePolling: false (ReadDirectoryChangesW) |
| Network / NFS / Docker volumes | usePolling: true, interval: 1000 |
Linux inotify exhaustion fix (symptom: watch silently stops working):
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
Windows: npm Scripts and .cmd Wrappers
PM2 cannot spawn .cmd shims (npm, npx, etc.) directly — they require cmd.exe.
// ecosystem.config.cjs — Windows npm script
{
name: "myapp",
script: "npm",
args: "start",
interpreter: "cmd",
interpreter_args: "/c"
}
For globally installed CLIs, find the real .js entry point:
# Linux/macOS
cat "$(which myapp)" | head -5
# Windows PowerShell
Get-Command myapp | Select-Object -ExpandProperty Source
Point script at the resolved .js file — never at the .cmd wrapper.
Terminal Suppression on Windows (CRITICAL)
All code that spawns subprocesses MUST use windowsHide: true to prevent popup windows.
// ❌ WRONG - will show popup windows on Windows
spawn('node', ['script.js']);
// ✅ CORRECT - hides windows, safe for all platforms
spawn('node', ['script.js'], { windowsHide: true });
Applies to all subprocess execution:
child_process.spawn()→{ windowsHide: true }child_process.exec()→{ windowsHide: true }child_process.execFile()→{ windowsHide: true }child_process.fork()→{ silent: true }(alternative for fork)
PM2-started processes automatically hide windows. Code-spawned subprocesses must explicitly set this. Forgetting creates visible popups during automation—unacceptable UX.
Windows 11+ wmic Error
PM2 uses wmic for process stats — removed in Windows 11+.
Symptom: Error: spawn wmic ENOENT in ~/.pm2/pm2.log.
Fix: npm install -g pm2@latest. App processes continue working despite the error.
Persistence on Reboot
| Platform | Method |
|---|---|
| Linux | pm2 startup && pm2 save (auto-detects systemd/upstart/openrc) |
| Windows | pm2-installer (Windows Service) |
pm2 save # snapshot current process list to ~/.pm2/dump.pm2
pm2 resurrect # restore saved list after manual daemon restart