PM2
— это обёртка вокруг node-cluster
для запуска nodeJS
приложения, в виде нескольких instance’s,
каждый из которых представлен отдельным процессом
. При этом, в стандартном применении, в качестве master
-а выступает внутренний скрипт пакета pm2
, а в качестве worker
-ов ваше приложение. Они всё так же могут слушать один и тот же порт. PM2
(а может и не он) сам будет распределять запросы между worker
-ами.
Рано или поздно может возникнуть необходимость коммуникации между worker
-ами. Как её осуществить? Изначально worker
-ы друг о друге ничего не знают, но если подключить require(‘pm2’)
, то через полученное API
можно добиться многого. Нормальной документации к этому API
, похоже не существует. Но большая часть доступных методов общая с CLI API
.
Для начала необходимо подключиться к pm2
из worker
-а:
const pm2 = require('pm2'); pm.conect(err => { // с этого момента можно использовать API });
Для получения всех запущенных pm2-процессов
(кроме master
-а) можно воспользоваться pm2.list()
. Он вернёт вам ВСЕ
запущенные им процессы, включая те, что никак не связаны с вашим приложением. Включая текущий
instance
тоже. Возвращённая пачка данных изобилует подробностями. 3-10 KiB
всякой ерунды на каждый worker
.
Отфильтровать оттуда текущий instance можно сравнив pmID
текущего процесса (process.env.pm_id
), с pmID
каждого worker
-а из списка. Для того чтобы выфильтровать лишние процессы, не связанные с вашим приложением, можно воспользоваться name
-ом (process.env.pm_id
). Это значение name из json-pm2-профиля
вашего приложения.
Метод list
несколько избыточен, мягко говоря. Можно получить только pmID
-ки worker
-ов по указанному name
-у. Для этого есть pm2.getProcessIdByName(name)
. Останется только выфильтровать из него pmID
текущего процесса.
А для того, чтобы разослать каждому из worker
-ов сообщение с данными, есть метод pm2.sendDataToProcessId(id, packet)
. Где packet
должен быть объектом с ключами: topic
(строка с ключом сообщения) и data
(сами данные).
Получать сообщения можно как штатными методами pm2
, через launchBus
(что у меня сделать не получилось), так и штатным process.on(‘message’, cb)
от nodejs
.
В итоге простой broadcast
можно организовать примерно так:
// при инициализации приложения pm.connect(err => {}); // отправка сообщения function broadcast(topic, data) { pm.getProcessIdByName(process.env.name, (err, ids) => { if(err) {} else ids .filter(i => i != process.env.pm_id) .forEach(id => { pm2.sendDataToProcessId(id, { topic, data }, err => {}); }); }); } // приём process.on('message', msg => { /* msg */ });
Ложка дёгтя
На getProcessIdByName
на моей машине уходит от 6ms
до 15ms
. Т.е. очень очень много. Код внутри по любому поводу формирует и гоняет между процессами груду данных. Используются теже механизмы, что и задействуются для pm2 monit
. Даже если запрашивался только ID
.
Почему нет никаких стандартных и удобных механизмом для коммуникации между процессами мне не ясно. Причём ни в pm2
, ни в nodeJS
. С nodeJS
впринципе всё ясно, ведь использование node-cluster
предполагает, что master
всему голова и сам всё порешает. Но в случае pm2
ситуация несколько иная.