Кластер
Исходный код: lib/cluster.js
Кластеры процессов Node.js можно использовать для запуска нескольких экземпляров Node.js, которые могут распределять рабочую нагрузку между потоками приложения. Если изоляция процессов не требуется, используйте вместо этого модуль worker_threads, который позволяет запускать несколько потоков приложения в одном экземпляре Node.js.
Модуль cluster позволяет легко создавать дочерние процессы, которые используют одни и те же серверные порты.
Модули JavaScript
import cluster from 'node:cluster';
import http from 'node:http';
import { availableParallelism } from 'node:os';
import process from 'node:process';
const numCPUs = availableParallelism();
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}CommonJS
const cluster = require('node:cluster');
const http = require('node:http');
const numCPUs = require('node:os').availableParallelism();
const process = require('node:process');
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
// In this case it is an HTTP server
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}Теперь при запуске Node.js рабочие процессы будут совместно использовать порт 8000:
$ node server.js Primary 3596 is running Worker 4324 started Worker 4520 started Worker 6056 started Worker 5644 started copy
В Windows пока невозможно настроить сервер именованных каналов в рабочем процессе.
Как это работает
Рабочие процессы создаются с помощью метода child_process.fork(), чтобы они могли обмениваться данными с родительским процессом через IPC и передавать серверные дескрипторы в обоих направлениях.
Модуль cluster поддерживает два способа распределения входящих подключений.
Первый (и используемый по умолчанию на всех платформах, кроме Windows) — это циклический алгоритм распределения: основной процесс прослушивает порт, принимает новые подключения и распределяет их между рабочими процессами по очереди, используя встроенные механизмы для предотвращения перегрузки рабочего процесса.
При втором подходе основной процесс создает сокет прослушивания и передает его заинтересованным рабочим процессам. Затем рабочие процессы напрямую принимают входящие подключения.
Теоретически второй подход должен обеспечивать наилучшую производительность. Однако на практике распределение, как правило, оказывается очень неравномерным из-за особенностей планировщика операционной системы. Наблюдались нагрузки, при которых более 70% всех подключений приходилось всего на два процесса из восьми.
Поскольку server.listen() передает большую часть работы основному процессу, есть три случая, в которых поведение обычного процесса Node.js и рабочего процесса кластера различается:
-
server.listen({fd: 7})Поскольку сообщение передается основному процессу, файловый дескриптор 7 в родительском процессе будет прослушиваться, а дескриптор будет передан рабочему процессу, вместо прослушивания того, на что указывает представление рабочего процесса о файловом дескрипторе с номером 7. -
server.listen(handle)При явном прослушивании дескрипторов рабочий процесс будет использовать переданный дескриптор, а не обращаться к основному процессу. -
server.listen(0)Обычно это приводит к тому, что серверы прослушивают случайный порт. Однако в кластере каждый рабочий процесс будет получать один и тот же «случайный» порт при каждом вызовеlisten(0). По сути, при первом вызове порт выбирается случайно, но впоследствии его значение предсказуемо. Чтобы прослушивать уникальный порт, сформируйте номер порта на основе идентификатора рабочего процесса кластера.
Node.js не предоставляет логику маршрутизации. Поэтому важно проектировать приложение так, чтобы оно не слишком полагалось на объекты данных в памяти для таких задач, как хранение сеансов и вход в систему.
Поскольку рабочие процессы являются отдельными процессами, их можно завершать или перезапускать в соответствии с потребностями программы, не затрагивая другие рабочие процессы. Пока работают хотя бы некоторые рабочие процессы, сервер продолжит принимать подключения. Если ни один рабочий процесс не работает, существующие подключения будут прерваны, а новые — отклонены. Однако Node.js не управляет количеством рабочих процессов автоматически. Приложение самостоятельно отвечает за управление пулом рабочих процессов в соответствии со своими потребностями.
Хотя основным сценарием использования модуля node:cluster является работа с сетью, его также можно применять в других случаях, требующих рабочих процессов.
Класс: Worker
- Наследует: <EventEmitter>
Объект Worker содержит все общедоступные сведения и методы рабочего процесса. В основном процессе его можно получить с помощью cluster.workers. В рабочем процессе его можно получить с помощью cluster.worker.
Событие: 'disconnect'
Аналогично событию cluster.on('disconnect'), но относится к этому рабочему процессу.
cluster.fork().on('disconnect', () => {
// Worker has disconnected
}); copy Событие: 'error'
Это событие совпадает с событием, предоставляемым child_process.fork().
В рабочем процессе также можно использовать process.on('error').
Событие: 'exit'
-
code<number> Код завершения, если процесс завершился обычным образом. -
signal<string> Название сигнала (например,'SIGHUP'), который привел к завершению процесса.
Аналогично событию cluster.on('exit'), но относится к этому рабочему процессу.
Модули JavaScript
import cluster from 'node:cluster';
if (cluster.isPrimary) {
const worker = cluster.fork();
worker.on('exit', (code, signal) => {
if (signal) {
console.log(`worker was killed by signal: ${signal}`);
} else if (code !== 0) {
console.log(`worker exited with error code: ${code}`);
} else {
console.log('worker success!');
}
});
}CommonJS
const cluster = require('node:cluster');
if (cluster.isPrimary) {
const worker = cluster.fork();
worker.on('exit', (code, signal) => {
if (signal) {
console.log(`worker was killed by signal: ${signal}`);
} else if (code !== 0) {
console.log(`worker exited with error code: ${code}`);
} else {
console.log('worker success!');
}
});
}Событие: 'listening'
-
address<Object>
Аналогично событию cluster.on('listening'), но относится к этому рабочему процессу.
Модули JavaScript
cluster.fork().on('listening', (address) => {
// Worker is listening
});CommonJS
cluster.fork().on('listening', (address) => {
// Worker is listening
});В рабочем процессе это событие не генерируется.
Событие: 'message'
-
message<Object> -
handle<undefined> | <Object>
Аналогично событию 'message' объекта cluster, но относится к этому рабочему процессу.
В рабочем процессе также можно использовать process.on('message').
См. событие process: 'message'.
Ниже приведен пример использования системы сообщений. В нем основной процесс ведет подсчет HTTP-запросов, полученных рабочими процессами:
Модули JavaScript
import cluster from 'node:cluster';
import http from 'node:http';
import { availableParallelism } from 'node:os';
import process from 'node:process';
if (cluster.isPrimary) {
// Keep track of http requests
let numReqs = 0;
setInterval(() => {
console.log(`numReqs = ${numReqs}`);
}, 1000);
// Count requests
function messageHandler(msg) {
if (msg.cmd && msg.cmd === 'notifyRequest') {
numReqs += 1;
}
}
// Start workers and listen for messages containing notifyRequest
const numCPUs = availableParallelism();
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
for (const id in cluster.workers) {
cluster.workers[id].on('message', messageHandler);
}
} else {
// Worker processes have a http server.
http.Server((req, res) => {
res.writeHead(200);
res.end('hello world\n');
// Notify primary about the request
process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}CommonJS
const cluster = require('node:cluster');
const http = require('node:http');
const numCPUs = require('node:os').availableParallelism();
const process = require('node:process');
if (cluster.isPrimary) {
// Keep track of http requests
let numReqs = 0;
setInterval(() => {
console.log(`numReqs = ${numReqs}`);
}, 1000);
// Count requests
function messageHandler(msg) {
if (msg.cmd && msg.cmd === 'notifyRequest') {
numReqs += 1;
}
}
// Start workers and listen for messages containing notifyRequest
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
for (const id in cluster.workers) {
cluster.workers[id].on('message', messageHandler);
}
} else {
// Worker processes have a http server.
http.Server((req, res) => {
res.writeHead(200);
res.end('hello world\n');
// Notify primary about the request
process.send({ cmd: 'notifyRequest' });
}).listen(8000);
}Событие: 'online'
Аналогично событию cluster.on('online'), но относится к этому рабочему процессу.
cluster.fork().on('online', () => {
// Worker is online
}); copy В рабочем процессе это событие не генерируется.
worker.disconnect()
- Возвращает: <cluster.Worker> Ссылка на
worker.
В рабочем процессе эта функция закрывает все серверы, ожидает события 'close' на этих серверах, а затем отключает канал IPC.
В основном процессе рабочему процессу отправляется внутреннее сообщение, вызывающее вызов им метода .disconnect().
Устанавливает значение .exitedAfterDisconnect.
После закрытия сервера он перестает принимать новые подключения, но их может принимать любой другой прослушивающий рабочий процесс. Существующим подключениям будет разрешено закрыться обычным образом. Когда подключений больше не останется, см. server.close(); канал IPC с рабочим процессом будет закрыт, что позволит ему корректно завершиться.
Это относится только к подключениям сервера; клиентские подключения рабочие процессы автоматически не закрывают, и отключение не ожидает их закрытия перед завершением.
В рабочем процессе существует process.disconnect, но это не данная функция, а disconnect().
Поскольку длительные подключения к серверу могут препятствовать отключению рабочих процессов, может быть полезно отправить сообщение, чтобы приложение выполнило необходимые действия для их закрытия. Также может быть полезно реализовать тайм-аут, по истечении которого рабочий процесс будет завершен, если за это время не было сгенерировано событие 'disconnect'.
if (cluster.isPrimary) {
const worker = cluster.fork();
let timeout;
worker.on('listening', (address) => {
worker.send('shutdown');
worker.disconnect();
timeout = setTimeout(() => {
worker.kill();
}, 2000);
});
worker.on('disconnect', () => {
clearTimeout(timeout);
});
} else if (cluster.isWorker) {
const net = require('node:net');
const server = net.createServer((socket) => {
// Connections never end
});
server.listen(8000);
process.on('message', (msg) => {
if (msg === 'shutdown') {
// Initiate graceful close of any connections to server
}
});
} copy
worker.exitedAfterDisconnect
- Тип: <boolean>
Это свойство равно true, если рабочий процесс завершился из-за .disconnect(). Если рабочий процесс завершился по любой другой причине, оно равно false. Если рабочий процесс еще не завершился, оно равно undefined.
Логическое значение worker.exitedAfterDisconnect позволяет различать добровольное и случайное завершение; основной процесс может решить не перезапускать рабочий процесс, опираясь на это значение.
cluster.on('exit', (worker, code, signal) => {
if (worker.exitedAfterDisconnect === true) {
console.log('Oh, it was just voluntary – no need to worry');
}
});
// kill worker
worker.kill(); copy
worker.id
- Тип: <integer>
Каждому новому рабочему процессу присваивается уникальный идентификатор, который хранится в id.
Пока рабочий процесс работает, этот идентификатор служит ключом для его поиска в cluster.workers.
worker.isConnected()
Эта функция возвращает true, если рабочий процесс подключен к основному процессу через канал IPC, и false в противном случае. Рабочий процесс подключается к основному после создания. Он отключается после генерации события 'disconnect'.
worker.isDead()
Эта функция возвращает true, если процесс рабочего процесса завершен (из-за выхода или получения сигнала). В противном случае она возвращает false.
Модули JavaScript
import cluster from 'node:cluster';
import http from 'node:http';
import { availableParallelism } from 'node:os';
import process from 'node:process';
const numCPUs = availableParallelism();
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('fork', (worker) => {
console.log('worker is dead:', worker.isDead());
});
cluster.on('exit', (worker, code, signal) => {
console.log('worker is dead:', worker.isDead());
});
} else {
// Workers can share any TCP connection. In this case, it is an HTTP server.
http.createServer((req, res) => {
res.writeHead(200);
res.end(`Current process\n ${process.pid}`);
process.kill(process.pid);
}).listen(8000);
}CommonJS
const cluster = require('node:cluster');
const http = require('node:http');
const numCPUs = require('node:os').availableParallelism();
const process = require('node:process');
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('fork', (worker) => {
console.log('worker is dead:', worker.isDead());
});
cluster.on('exit', (worker, code, signal) => {
console.log('worker is dead:', worker.isDead());
});
} else {
// Workers can share any TCP connection. In this case, it is an HTTP server.
http.createServer((req, res) => {
res.writeHead(200);
res.end(`Current process\n ${process.pid}`);
process.kill(process.pid);
}).listen(8000);
}
worker.kill([signal])
-
signal<string> Название сигнала завершения, отправляемого процессу рабочего процесса. По умолчанию:'SIGTERM'
Эта функция завершает рабочий процесс. В основном процессе она делает это, отключая worker.process, а после отключения — завершая процесс с помощью signal. В рабочем процессе она завершает процесс с помощью signal.
Функция kill() завершает процесс рабочего процесса, не дожидаясь корректного отключения; ее поведение совпадает с поведением worker.process.kill().
Для обратной совместимости этот метод также доступен под именем worker.destroy().
В рабочем процессе существует process.kill(), но это не данная функция, а kill().
worker.process
- Тип: <ChildProcess>
Все рабочие процессы создаются с помощью child_process.fork(); объект, возвращенный этой функцией, сохраняется как .process. В рабочем процессе сохраняется глобальное значение process.
См.: Модуль дочерних процессов.
Рабочие процессы вызывают process.exit(0), если для process происходит событие 'disconnect' и .exitedAfterDisconnect не равно true. Это защищает от случайного отключения.
worker.send(message[, sendHandle[, options]][, callback])
-
message<Object> -
sendHandle<Handle> -
options<Object> Аргументoptions, если он указан, представляет собой объект, используемый для настройки отправки некоторых типов дескрипторов.optionsподдерживает следующие свойства:-
keepOpen<boolean> Значение, которое можно использовать при передаче экземпляровnet.Socket. Если значениеtrue, сокет остается открытым в отправляющем процессе. По умолчанию:false.
-
-
callback<Function> - Возвращает: <boolean>
Отправляет сообщение рабочему или основному процессу, при необходимости передавая дескриптор.
В основном процессе эта функция отправляет сообщение определенному рабочему процессу. Она идентична методу ChildProcess.send().
В рабочем процессе эта функция отправляет сообщение основному процессу. Она идентична process.send().
В этом примере все сообщения от основного процесса отправляются обратно ему:
if (cluster.isPrimary) {
const worker = cluster.fork();
worker.send('hi there');
} else if (cluster.isWorker) {
process.on('message', (msg) => {
process.send(msg);
});
} copy Событие: 'disconnect'
-
worker<cluster.Worker>
Генерируется после отключения канала IPC рабочего процесса. Это может произойти, когда рабочий процесс корректно завершается, принудительно завершается или отключается вручную (например, с помощью worker.disconnect()).
Между событиями 'disconnect' и 'exit' может пройти некоторое время. Эти события можно использовать, чтобы определить, застрял ли процесс на этапе очистки или существуют ли длительные подключения.
cluster.on('disconnect', (worker) => {
console.log(`The worker #${worker.id} has disconnected`);
}); copy Событие: 'exit'
-
worker<cluster.Worker> -
code<number> Код завершения, если процесс завершился обычным образом. -
signal<string> Название сигнала (например,'SIGHUP'), который привел к завершению процесса.
Когда любой из рабочих процессов завершается, модуль cluster генерирует событие 'exit'.
Это событие можно использовать для перезапуска рабочего процесса, повторно вызвав .fork().
cluster.on('exit', (worker, code, signal) => {
console.log('worker %d died (%s). restarting...',
worker.process.pid, signal || code);
cluster.fork();
}); copy Событие: 'fork'
-
worker<cluster.Worker>
Когда создается новый рабочий процесс, модуль cluster генерирует событие 'fork'. Это можно использовать для регистрации активности рабочих процессов и создания пользовательского тайм-аута.
const timeouts = [];
function errorMsg() {
console.error('Something must be wrong with the connection ...');
}
cluster.on('fork', (worker) => {
timeouts[worker.id] = setTimeout(errorMsg, 2000);
});
cluster.on('listening', (worker, address) => {
clearTimeout(timeouts[worker.id]);
});
cluster.on('exit', (worker, code, signal) => {
clearTimeout(timeouts[worker.id]);
errorMsg();
}); copy Событие: 'listening'
-
worker<cluster.Worker> -
address<Object>
После вызова listen() из рабочего процесса, когда на сервере генерируется событие 'listening', в основном процессе для cluster также будет сгенерировано событие 'listening'.
Обработчик события вызывается с двумя аргументами: worker содержит объект рабочего процесса, а объект address содержит следующие свойства подключения: address, port и addressType. Это очень полезно, если рабочий процесс прослушивает более одного адреса.
cluster.on('listening', (worker, address) => {
console.log(
`A worker is now connected to ${address.address}:${address.port}`);
}); copy Значение addressType может быть одним из следующих:
-
4(TCPv4) -
6(TCPv6) -
-1(сокет домена Unix) -
'udp4'или'udp6'(UDPv4 или UDPv6)
Событие: 'message'
-
worker<cluster.Worker> -
message<Object> -
handle<undefined> | <Object>
Генерируется, когда основной процесс кластера получает сообщение от любого рабочего процесса.
Событие: 'online'
-
worker<cluster.Worker>
После создания нового рабочего процесса он должен ответить сообщением о готовности к работе. Когда основной процесс получает такое сообщение, он генерирует это событие. События 'fork' и 'online' различаются тем, что первое генерируется при создании рабочего процесса основным процессом, а 'online' — когда рабочий процесс начинает работу.
cluster.on('online', (worker) => {
console.log('Yay, the worker responded after it was forked');
}); copy Событие: 'setup'
-
settings<Object>
Генерируется при каждом вызове .setupPrimary().
Объект settings — это объект cluster.settings на момент вызова .setupPrimary(); он носит рекомендательный характер, поскольку в течение одного такта может быть выполнено несколько вызовов .setupPrimary().
Если важна точность, используйте cluster.settings.
cluster.disconnect([callback])
-
callback<Function> Вызывается, когда все рабочие процессы отключены, а дескрипторы закрыты.
Вызывает .disconnect() для каждого рабочего процесса в cluster.workers.
После отключения все внутренние дескрипторы закрываются, что позволяет основному процессу корректно завершиться, если не ожидается никаких других событий.
Метод принимает необязательный аргумент обратного вызова, который будет вызван по завершении.
Этот метод можно вызвать только из основного процесса.
cluster.fork([env])
-
env<Object> Пары ключ-значение, добавляемые в окружение процесса рабочего процесса. - Возвращает: <cluster.Worker>
Создает новый процесс рабочего процесса.
Этот метод можно вызвать только из основного процесса.
cluster.isMaster
Устаревший псевдоним для cluster.isPrimary.
cluster.isPrimary
- Тип: <boolean>
Значение true, если процесс является основным. Это определяется по process.env.NODE_UNIQUE_ID. Если process.env.NODE_UNIQUE_ID не определено, то isPrimary равно true.
cluster.isWorker
- Тип: <boolean>
Значение true, если процесс не является основным (это отрицание cluster.isPrimary).
cluster.schedulingPolicy
Политика планирования: cluster.SCHED_RR для циклического распределения или cluster.SCHED_NONE, чтобы передать управление операционной системе. Это глобальный параметр, который фактически фиксируется после создания первого рабочего процесса или вызова .setupPrimary() — в зависимости от того, что произойдет раньше.
SCHED_RR используется по умолчанию во всех операционных системах, кроме Windows. В Windows будет использоваться SCHED_RR, когда libuv сможет эффективно распределять дескрипторы IOCP без существенного снижения производительности.
Значение cluster.schedulingPolicy также можно задать с помощью переменной окружения NODE_CLUSTER_SCHED_POLICY. Допустимые значения: 'rr' и 'none'.
cluster.settings
- Тип: <Object>
-
execArgv<string[]> Список строковых аргументов, передаваемых исполняемому файлу Node.js. По умолчанию:process.execArgv. -
exec<string> Путь к файлу рабочего процесса. По умолчанию:process.argv[1]. -
args<string[]> Строковые аргументы, передаваемые рабочему процессу. По умолчанию:process.argv.slice(2). -
cwd<string> Текущий рабочий каталог процесса рабочего процесса. По умолчанию:undefined(наследуется от родительского процесса). -
serialization<string> Задает тип сериализации, используемый для отправки сообщений между процессами. Допустимые значения:'json'и'advanced'. Дополнительные сведения см. в разделе Расширенная сериализация дляchild_process. По умолчанию:false. -
silent<boolean> Нужно ли отправлять вывод в стандартные потоки ввода-вывода родительского процесса. По умолчанию:false. -
stdio<Array> Настраивает стандартные потоки ввода-вывода создаваемых процессов. Поскольку для работы модулю cluster требуется IPC, эта конфигурация должна содержать запись'ipc'. Если задан этот параметр, он переопределяетsilent. См. параметрыstdioметодаchild_process.spawn(). -
uid<number> Задает идентификатор пользователя процесса. (См.setuid(2).) -
gid<number> Задает идентификатор группы процесса. (См.setgid(2).) -
inspectPort<number> | <Function> Задает порт инспектора рабочего процесса. Это может быть число или функция без аргументов, возвращающая число. По умолчанию каждый рабочий процесс получает собственный порт, начиная сprocess.debugPortосновного процесса и далее по возрастанию. -
windowsHide<boolean> Скрывает окно консоли создаваемых процессов, которое обычно появляется в Windows. По умолчанию:false.
-
После вызова .setupPrimary() (или .fork()) этот объект настроек будет содержать параметры, включая значения по умолчанию.
Этот объект не предназначен для изменения или ручной установки.
cluster.setupMaster([settings])
Устаревший псевдоним для .setupPrimary().
cluster.setupPrimary([settings])
-
settings<Object> См.cluster.settings.
setupPrimary используется для изменения поведения 'fork' по умолчанию. После вызова параметры будут доступны в cluster.settings.
Изменения параметров влияют только на последующие вызовы .fork() и не влияют на уже работающие воркеры.
Единственный атрибут воркера, который нельзя задать через .setupPrimary(), — это env, передаваемый в .fork().
Указанные выше значения по умолчанию применяются только при первом вызове; при последующих вызовах используются значения, актуальные на момент вызова cluster.setupPrimary().
Модули JavaScript
import cluster from 'node:cluster';
cluster.setupPrimary({
exec: 'worker.js',
args: ['--use', 'https'],
silent: true,
});
cluster.fork(); // https worker
cluster.setupPrimary({
exec: 'worker.js',
args: ['--use', 'http'],
});
cluster.fork(); // http workerCommonJS
const cluster = require('node:cluster');
cluster.setupPrimary({
exec: 'worker.js',
args: ['--use', 'https'],
silent: true,
});
cluster.fork(); // https worker
cluster.setupPrimary({
exec: 'worker.js',
args: ['--use', 'http'],
});
cluster.fork(); // http workerЭтот метод можно вызвать только из основного процесса.
cluster.worker
- Тип: <Object>
Ссылка на объект текущего воркера. Недоступна в основном процессе.
Модули JavaScript
import cluster from 'node:cluster';
if (cluster.isPrimary) {
console.log('I am primary');
cluster.fork();
cluster.fork();
} else if (cluster.isWorker) {
console.log(`I am worker #${cluster.worker.id}`);
}CommonJS
const cluster = require('node:cluster');
if (cluster.isPrimary) {
console.log('I am primary');
cluster.fork();
cluster.fork();
} else if (cluster.isWorker) {
console.log(`I am worker #${cluster.worker.id}`);
}
cluster.workers
- Тип: <Object>
Хеш-таблица активных объектов воркеров, ключами которой являются значения поля id. Это позволяет легко перебрать все воркеры. Она доступна только в основном процессе.
Воркер удаляется из cluster.workers после отключения и завершения работы. Заранее определить порядок этих двух событий нельзя. Однако гарантируется, что удаление из списка cluster.workers происходит до отправки последнего события 'disconnect' или 'exit'.
Модули JavaScript
import cluster from 'node:cluster';
for (const worker of Object.values(cluster.workers)) {
worker.send('big announcement to all workers');
}CommonJS
const cluster = require('node:cluster');
for (const worker of Object.values(cluster.workers)) {
worker.send('big announcement to all workers');
}
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v24.x/docs/api/cluster.html