PM2 для JavaScript (Node.js): полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

PM2 для JavaScript (Node.js): полное руководство с примерами

1. Что это и зачем нужна

PM2 (Process Manager 2) — это мощный менеджер процессов для приложений на Node.js, предназначенный для использования в production-среде. Он позволяет запускать, останавливать, перезагружать и мониторить Node.js-приложения, обеспечивая их высокую доступность и отказоустойчивость. PM2 автоматически перезапускает упавшие процессы, распределяет нагрузку между несколькими экземплярами приложения (кластеризация), предоставляет встроенный балансировщик нагрузки и поддерживает бесшовные (graceful) перезагрузки без простоев.

В production-среде Node.js-приложения часто сталкиваются с неожиданными ошибками, утечками памяти или перегрузками. PM2 решает эти проблемы, выступая в роли «демона-хранителя»: он отслеживает состояние каждого процесса, логирует stdout/stderr, предоставляет метрики производительности (CPU, память) и позволяет управлять приложением через CLI или API. Без PM2 разработчику пришлось бы вручную писать скрипты для перезапуска, мониторинга и масштабирования — PM2 автоматизирует все эти задачи.

Ключевые возможности PM2 включают: кластеризацию (запуск нескольких воркеров на всех ядрах CPU), zero-downtime перезагрузку, управление окружением (development/production), встроенный мониторинг (pm2 monit), поддержку конфигурационных файлов (ecosystem.config.js) и интеграцию с системами инициализации (systemd, upstart) для автозапуска при старте сервера.

2. Установка

PM2 устанавливается глобально через npm (Node Package Manager). Точная команда:

npm install -g pm2

Для установки конкретной версии:

npm install -g pm2@5.3.0

После установки проверьте версию:

pm2 --version

3. Быстрый старт — минимальный рабочий пример

Создайте простое Node.js-приложение app.js:

// app.js
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from PM2!\n');
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Запустите приложение через PM2:

pm2 start app.js --name my-app

Проверьте статус:

pm2 status

Остановите приложение:

pm2 stop my-app

4. Основные методы/функции/классы

4.1. pm2.start() — Запуск приложения

Сигнатура: pm2.start(script, options, callback)

Что делает: Запускает указанный скрипт как процесс PM2 с заданными опциями (имя, количество инстансов, переменные окружения).

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.start({
    script: 'app.js',
    name: 'my-app',
    instances: 2, // запустить 2 инстанса
    exec_mode: 'cluster', // кластерный режим
    env: {
      NODE_ENV: 'production',
      PORT: 3000
    }
  }, (err, apps) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('App started:', apps);
    pm2.disconnect();
  });
});

4.2. pm2.stop() — Остановка процесса

Сигнатура: pm2.stop(process, callback)

Что делает: Останавливает указанный процесс (по имени, ID или всем процессам).

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  // Остановить процесс по имени
  pm2.stop('my-app', (err, proc) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Process stopped:', proc);
    pm2.disconnect();
  });
});

4.3. pm2.restart() — Перезапуск процесса

Сигнатура: pm2.restart(process, callback)

Что делает: Перезапускает указанный процесс (или все процессы). При graceful restart приложение сначала получает сигнал SIGINT, ждет завершения текущих соединений, затем перезапускается.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.restart('my-app', (err, proc) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Process restarted:', proc);
    pm2.disconnect();
  });
});

4.4. pm2.delete() — Удаление процесса из списка PM2

Сигнатура: pm2.delete(process, callback)

Что делает: Останавливает процесс и удаляет его из списка управляемых процессов PM2.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.delete('my-app', (err) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Process deleted');
    pm2.disconnect();
  });
});

4.5. pm2.list() — Получение списка всех процессов

Сигнатура: pm2.list(callback)

Что делает: Возвращает массив объектов, описывающих все процессы, управляемые PM2 (статус, имя, ID, использование CPU/памяти, uptime).

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.list((err, list) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Process list:', JSON.stringify(list, null, 2));
    pm2.disconnect();
  });
});

4.6. pm2.describe() — Детальная информация о процессе

Сигнатура: pm2.describe(process, callback)

Что делает: Возвращает подробную информацию о конкретном процессе: версия Node.js, аргументы командной строки, переменные окружения, путь к скрипту, количество рестартов и т.д.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.describe('my-app', (err, proc) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Process details:', JSON.stringify(proc, null, 2));
    pm2.disconnect();
  });
});

4.7. pm2.reload() — Бесшовная перезагрузка (graceful reload)

Сигнатура: pm2.reload(process, callback)

Что делает: Выполняет zero-downtime перезагрузку для кластеризованных приложений: перезапускает воркеры по одному, чтобы приложение продолжало обрабатывать запросы без простоев.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.reload('my-app', (err, proc) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Graceful reload completed:', proc);
    pm2.disconnect();
  });
});

4.8. pm2.flush() — Очистка логов

Сигнатура: pm2.flush(process, callback)

Что делает: Очищает все логи (stdout и stderr) для указанного процесса или всех процессов.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.flush('my-app', (err) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Logs flushed');
    pm2.disconnect();
  });
});

4.9. pm2.sendSignalToProcessName() — Отправка сигнала процессу

Сигнатура: pm2.sendSignalToProcessName(signal, process, callback)

Что делает: Отправляет произвольный сигнал (например, SIGUSR2, SIGINT) указанному процессу для кастомной обработки.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.sendSignalToProcessName('SIGUSR2', 'my-app', (err) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }
    console.log('Signal sent');
    pm2.disconnect();
  });
});

4.10. pm2.launchBus() — Подписка на события PM2

Сигнатура: pm2.launchBus(callback)

Что делает: Создает шину событий (EventEmitter) для подписки на события PM2: запуск, остановка, перезапуск, ошибки процессов и т.д.

Рабочий пример кода:

const pm2 = require('pm2');

pm2.connect((err) => {
  if (err) {
    console.error(err);
    process.exit(2);
  }

  pm2.launchBus((err, bus) => {
    if (err) {
      console.error(err);
      return pm2.disconnect();
    }

    // Подписываемся на событие остановки процесса
    bus.on('process:event', (event) => {
      console.log('Event received:', event);
    });

    // Подписываемся на логи
    bus.on('log:out', (data) => {
      console.log('Log output:', data.data);
    });

    // Подписываемся на ошибки
    bus.on('log:err', (data) => {
      console.error('Log error:', data.data);
    });
  });
});

5. Реальный практический пример

Ниже представлен полноценный пример production-ready Express-приложения с использованием PM2 API для управления процессами, graceful shutdown и мониторинга.

// server.js — основное приложение
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// Graceful shutdown handler
process.on('SIGINT', () => {
  console.log('Received SIGINT. Performing graceful shutdown...');
  server.close(() => {
    console.log('HTTP server closed.');
    process.exit(0);
  });
});

process.on('SIGTERM', () => {
  console.log('Received SIGTERM. Performing graceful shutdown...');
  server.close(() => {
    console.log('HTTP server closed.');
    process.exit(0);
  });
});

app.get('/', (req, res) => {
  res.json({ message: 'Hello from PM2-managed app!', pid: process.pid });
});

app.get('/health', (req, res) => {
  res.json({ status: 'ok', uptime: process.uptime() });
});

const server = app.listen(PORT, () => {
  console.log(`Worker ${process.pid} started on port ${PORT}`);
});

// pm2-manager.js — скрипт для программного управления PM2
const pm2 = require('pm2');
const path = require('path');

class PM2Manager {
  constructor() {
    this.connected = false;
  }

  connect() {
    return new Promise((resolve, reject) => {
      pm2.connect((err) => {
        if (err) {
          reject(err);
          return;
        }
        this.connected = true;
        resolve();
      });
    });
  }

  disconnect() {
    if (this.connected) {
      pm2.disconnect();
      this.connected = false;
    }
  }

  async startApp(config = {}) {
    const defaultConfig = {
      script: path.join(__dirname, 'server.js'),
      name: 'express-app',
      instances: 'max', // использовать все ядра CPU
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'production',
        PORT: 3000
      },
      max_memory_restart: '500M', // перезапуск при превышении 500MB
      error_file: './logs/err.log',
      out_file: './logs/out.log',
      log_date_format: 'YYYY-MM-DD HH:mm:ss',
      merge_logs: true,
      autorestart: true,
      watch: false,
      max_restarts: 10,
      restart_delay: 1000
    };

    const finalConfig = { ...defaultConfig, ...config };

    return new Promise((resolve, reject) => {
      pm2.start(finalConfig, (err, apps) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(apps);
      });
    });
  }

  async gracefulReload(appName) {
    return new Promise((resolve, reject) => {
      pm2.reload(appName, { timeout: 30000 }, (err, proc) => {
        if (err) {
          reject(err);
          return                    

Рекомендаций