Manage Long-Running Processes with PM2

AIRabbit - Feb 11 - - Dev Community

Ever had a Node.js script that needs to run for hours, updating your database continuously? Let me show you how we handle this at our price comparison service.

Our system needs to constantly fetch prices from different suppliers and update MongoDB. It's a beast that runs 24/7, processing thousands of products. Here's how we tamed it with PM2.

You might be thinking "I'll just run it with node script.js and maybe add some nohup or screen session." Been there, done that. But then:

  • Your script crashes? You're not even aware until customers complain
  • Memory leak? Have fun SSH-ing at 3 AM to restart it
  • Need logs? Good luck digging through random .log files
  • Want metrics? "I'll just add console.log everywhere"
  • Multiple servers? Now you're juggling multiple SSH sessions

PM2 solves all of this. It's like having a professional DevOps team in a single command:

1. Basic Setup

First, install PM2 globally:

npm install -g pm2
Enter fullscreen mode Exit fullscreen mode

Your price scraper (price-scraper.js):

async function main() {
  while(true) {
    console.log('Fetching new prices...');
    await updatePrices();
    await sleep(60000); // Wait 1 minute
  }
}

main().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Your ecosystem.config.js:

module.exports = {
  apps: [{
    name: 'price-scraper',
    script: 'price-scraper.js',
    instances: 1,
    max_memory_restart: '1G',
    error_file: 'logs/error.log',
    out_file: 'logs/out.log',
    merge_logs: true,
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
    env: {
      NODE_ENV: 'production'
    }
  }]
}
Enter fullscreen mode Exit fullscreen mode

2. Essential Commands

Start your app:

pm2 start ecosystem.config.js
Enter fullscreen mode Exit fullscreen mode

Stop everything:

pm2 stop all
Enter fullscreen mode Exit fullscreen mode

Stop specific app:

pm2 stop price-scraper
Enter fullscreen mode Exit fullscreen mode

Restart:

pm2 restart price-scraper
Enter fullscreen mode Exit fullscreen mode

Delete from PM2:

pm2 delete price-scraper
Enter fullscreen mode Exit fullscreen mode

3. Real-time Monitoring

Terminal monitoring:

pm2 monit
Enter fullscreen mode Exit fullscreen mode

View logs:

pm2 logs              # All logs
pm2 logs price-scraper # App specific
pm2 logs --lines 200  # Last 200 lines
Enter fullscreen mode Exit fullscreen mode

Check status:

pm2 status
pm2 list             # Same as status
Enter fullscreen mode Exit fullscreen mode

4. PM2 Plus (app.pm2.io) Integration

Now imagine you want to monitor your long-running application from anywhere. you can use the pm2 dashboard for this. In a nutshell, your pm2 sends the trace of the applications it manages to pm2.io. and you can see the current status at any time.

To use the PM2 Plus dashboard:

  1. Install PM2 Runtime on your server:
npm install -g pm2
Enter fullscreen mode Exit fullscreen mode
  1. Link PM2 to PM2.io (get your link command after creating a bucket on app.pm2.io):
pm2 link xxxx  # Replace xxxx with your bucket's link command
Enter fullscreen mode Exit fullscreen mode
  1. Start your application:
pm2 start ecosystem.config.js
Enter fullscreen mode Exit fullscreen mode

Now you can add custom metrics to your app:

const io = require('@pm2/io')

// Counter metric
const pricesUpdated = io.counter({
  name: 'Prices Updated'
})

// Gauge for memory
const memoryUsage = io.metric({
  name: 'Memory Usage'
})

async function updatePrices() {
  pricesUpdated.inc()
  memoryUsage.set(process.memoryUsage().heapUsed)
  // ... rest of your code
}
Enter fullscreen mode Exit fullscreen mode

Now on app.pm2.io you'll see:

  • Real-time metrics
  • CPU/Memory usage
  • Custom metrics you added
  • Exception tracking
  • Log management
  • Deployment history

5. Deployment Example

Save your deployment config:

pm2 save
Enter fullscreen mode Exit fullscreen mode

Start on system boot:

pm2 startup
Enter fullscreen mode Exit fullscreen mode

Deploy new version:

git pull
pm2 reload ecosystem.config.js
Enter fullscreen mode Exit fullscreen mode

6. Health Checks

Add health endpoint to your app:

const http = require('http');

http.createServer((req, res) => {
  if (req.url === '/health') {
    res.writeHead(200);
    res.end('OK');
  }
}).listen(9209);
Enter fullscreen mode Exit fullscreen mode

Monitor in ecosystem.config.js:

module.exports = {
  apps: [{
    name: 'price-scraper',
    // ... other config
    exp_backoff_restart_delay: 100,
    max_restarts: 10,
    min_uptime: '5m',
    listen_timeout: 8000,
    shutdown_with_message: true
  }]
}
Enter fullscreen mode Exit fullscreen mode

Wrap-Up

Now you've got a complete setup with automatic restarts keeping your app alive 24/7, system boot integration so you never worry about server reboots, real-time monitoring showing you exactly what's happening under the hood, custom metrics tracking whatever matters to your business, health checks catching problems before users do, and centralized log management that actually makes sense - all beautifully visible in your app.pm2.io dashboard

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .