misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_article', action: 'view', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

Broadcast в PM2

 — 
5 апреля 2016 00:00

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 ситуация несколько иная.

Теги:
pm2 node JavaScript
Комментарии
Оставить комментарий
Оставить комментарий:
Отправить через:
Предпросмотр
modules/comment
window._Comment_content_article_141 = new classes.Comment( '#comment_block_content_article_141', { type: 'content_article', node_id: '141', user: 1, user_id: 0, admin: 0, view_time: null, msg: { empty: 'Комментарий пуст', ask_link: 'Ссылка:', ask_img: 'Ссылка на изображение:' } });