Cluster#

安定性: 2 - Stable

ソースコード: lib/cluster.js

Node.jsプロセスのクラスターは、Node.jsの複数インスタンスを実行し、アプリケーションスレッド間でワークロードを分散するために使用できます。プロセスの分離が不要な場合は、代わりにworker_threadsモジュールを使用してください。これにより、単一のNode.jsインスタンス内で複数のアプリケーションスレッドを実行できます。

clusterモジュールを使用すると、すべてのサーバーポートを共有する子プロセスを簡単に作成できます。

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`);
}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 

Windowsでは、ワーカー内で名前付きパイプサーバーをセットアップすることはまだできません。

仕組み#

ワーカープロセスはchild_process.fork()メソッドを使用して生成されるため、IPCを介して親と通信し、サーバーハンドルを相互に受け渡すことができます。

clusterモジュールは、着信接続を分散する2つの方法をサポートしています。

1つ目(そしてWindowsを除くすべてのプラットフォームでのデフォルト)はラウンドロビンアプローチです。プライマリープロセスがポートをリッスンし、新しい接続を受け付け、ワーカープロセスに過負荷をかけないようにする組み込みの仕組みを使用して、ラウンドロビン方式でワーカーに分散します。

2つ目のアプローチは、プライマリープロセスがリッスンソケットを作成し、それを対象のワーカーに送信する方法です。ワーカーはその後、着信接続を直接受け付けます。

理論的には、2つ目のアプローチが最高のパフォーマンスを発揮するはずです。しかし実際には、オペレーティングシステムのスケジューラの気まぐれにより、分散は非常に不均衡になる傾向があります。合計8つのプロセスのうち、すべての接続の70%以上がたった2つのプロセスに集中したという事例も観察されています。

server.listen()はほとんどの作業をプライマリープロセスに委譲するため、通常のNode.jsプロセスとクラスターワーカーの動作が異なるケースが3つあります。

  1. server.listen({fd: 7}) メッセージがプライマリーに渡されるため、ワーカーがファイルディスクリプタ番号7として認識しているものをリッスンするのではなく、親のファイルディスクリプタ7がリッスンされ、そのハンドルがワーカーに渡されます。
  2. server.listen(handle) ハンドルを明示的にリッスンすると、ワーカーはプライマリープロセスと通信するのではなく、指定されたハンドルを使用します。
  3. server.listen(0) 通常、これによりサーバーはランダムなポートでリッスンします。しかし、クラスターでは、各ワーカーがlisten(0)を実行するたびに、同じ「ランダムな」ポートを受け取ります。つまり、ポートは最初はランダムですが、その後は予測可能です。一意のポートでリッスンするには、クラスターワーカーIDに基づいてポート番号を生成してください。

Node.jsはルーティングロジックを提供しません。そのため、セッションやログインのようなものについて、インメモリのデータオブジェクトに過度に依存しないようにアプリケーションを設計することが重要です。

ワーカーはすべて個別のプロセスであるため、プログラムのニーズに応じて、他のワーカーに影響を与えることなく強制終了または再生成できます。ワーカーがいくつか生き残っている限り、サーバーは接続を受け付け続けます。生きているワーカーがいない場合、既存の接続は切断され、新しい接続は拒否されます。ただし、Node.jsはワーカーの数を自動的に管理しません。自身のニーズに基づいてワーカープールを管理するのは、アプリケーションの責任です。

node:clusterモジュールの主な使用例はネットワーキングですが、ワーカープロセスを必要とする他のユースケースにも使用できます。

クラス: Worker#

Workerオブジェクトには、ワーカーに関するすべての公開情報とメソッドが含まれています。プライマリーではcluster.workersを使用して取得できます。ワーカーではcluster.workerを使用して取得できます。

イベント: 'disconnect'#

cluster.on('disconnect')イベントに似ていますが、このワーカーに固有のものです。

cluster.fork().on('disconnect', () => {
  // Worker has disconnected
}); 

イベント: 'error'#

このイベントはchild_process.fork()によって提供されるものと同じです。

ワーカー内では、process.on('error')も使用できます。

イベント: 'exit'#

  • code <number> 正常に終了した場合の終了コード。
  • signal <string> プロセスを強制終了させたシグナルの名前(例:'SIGHUP')。

cluster.on('exit')イベントに似ていますが、このワーカーに固有のものです。

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!');
    }
  });
}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'#

cluster.on('listening')イベントに似ていますが、このワーカーに固有のものです。

cluster.fork().on('listening', (address) => {
  // Worker is listening
});cluster.fork().on('listening', (address) => {
  // Worker is listening
});

ワーカーでは発行されません。

イベント: 'message'#

cluster'message'イベントに似ていますが、このワーカーに固有のものです。

ワーカー内では、process.on('message')も使用できます。

process イベント: 'message'を参照してください。

以下はメッセージシステムを使用した例です。ワーカーが受信したHTTPリクエストの数をプライマリープロセスでカウントし続けます。

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);
}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
}); 

ワーカーでは発行されません。

worker.disconnect()#

ワーカーでは、この関数はすべてのサーバーを閉じ、それらのサーバーで'close'イベントを待ち、その後IPCチャネルを切断します。

プライマリーでは、内部メッセージがワーカーに送信され、ワーカー自身で.disconnect()を呼び出すようになります。

.exitedAfterDisconnectが設定される原因となります。

サーバーが閉じられた後、新しい接続は受け付けられなくなりますが、他のリッスンしているワーカーによって接続が受け付けられる場合があります。既存の接続は通常通り閉じることが許可されます。接続がなくなると、server.close()を参照してください、ワーカーへのIPCチャネルが閉じ、正常に終了できるようになります。

上記はサーバー接続にのみ適用され、クライアント接続はワーカーによって自動的に閉じられることはなく、disconnectは終了する前にそれらが閉じるのを待ちません。

ワーカーには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
    }
  });
} 

worker.exitedAfterDisconnect#

このプロパティは、ワーカーが.disconnect()によって終了した場合はtrueです。ワーカーが他の方法で終了した場合は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(); 

worker.id#

新しいワーカーにはそれぞれ一意のIDが与えられ、このIDはidに保存されます。

ワーカーが生きている間、これはcluster.workers内でワーカーをインデックスするためのキーです。

worker.isConnected()#

この関数は、ワーカーがIPCチャネルを介してプライマリーに接続されている場合はtrueを、そうでない場合はfalseを返します。ワーカーは作成された後にプライマリーに接続されます。'disconnect'イベントが発行された後に切断されます。

worker.isDead()#

この関数は、ワーカーのプロセスが終了した場合(終了またはシグナルによる強制終了)はtrueを返します。それ以外の場合はfalseを返します。

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);
}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> ワーカープロセスに送信するkillシグナルの名前。デフォルト: 'SIGTERM'

この関数はワーカーを強制終了します。プライマリーワーカーでは、worker.processを切断し、切断後にsignalで強制終了することでこれを行います。ワーカーでは、プロセスをsignalで強制終了することで行います。

kill()関数は、正常な切断を待たずにワーカープロセスを強制終了します。これはworker.process.kill()と同じ動作です。

このメソッドは、後方互換性のためにworker.destroy()としてエイリアスされています。

ワーカーにはprocess.kill()が存在しますが、それはこの関数ではなく、kill()です。

worker.process#

すべてのワーカーはchild_process.fork()を使用して作成され、この関数から返されたオブジェクトは.processとして保存されます。ワーカーでは、グローバルなprocessが保存されます。

参照: 子プロセスモジュール

process'disconnect'イベントが発生し、かつ.exitedAfterDisconnecttrueでない場合、ワーカーはprocess.exit(0)を呼び出します。これは偶発的な切断から保護します。

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);
  });
} 

イベント: 'disconnect'#

ワーカーのIPCチャネルが切断された後に発行されます。これは、ワーカーが正常に終了したとき、強制終了されたとき、または手動で切断されたとき(worker.disconnect()など)に発生します。

'disconnect'イベントと'exit'イベントの間には遅延がある場合があります。これらのイベントは、プロセスがクリーンアップでスタックしているか、または長寿命の接続があるかどうかを検出するために使用できます。

cluster.on('disconnect', (worker) => {
  console.log(`The worker #${worker.id} has disconnected`);
}); 

イベント: '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();
}); 

child_process イベント: 'exit'を参照してください。

イベント: 'fork'#

新しいワーカーがフォークされると、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();
}); 

イベント: 'listening'#

ワーカーからlisten()を呼び出した後、サーバーで'listening'イベントが発行されると、プライマリーのclusterでも'listening'イベントが発行されます。

イベントハンドラは2つの引数で実行されます。workerにはワーカーオブジェクトが含まれ、addressオブジェクトにはaddressportaddressTypeの接続プロパティが含まれます。これは、ワーカーが複数のアドレスをリッスンしている場合に非常に便利です。

cluster.on('listening', (worker, address) => {
  console.log(
    `A worker is now connected to ${address.address}:${address.port}`);
}); 

addressTypeは次のいずれかです。

  • 4 (TCPv4)
  • 6 (TCPv6)
  • -1 (Unixドメインソケット)
  • 'udp4' または 'udp6' (UDPv4 または UDPv6)

イベント: 'message'#

クラスターのプライマリーがいずれかのワーカーからメッセージを受信したときに発行されます。

child_process イベント: 'message'を参照してください。

イベント: 'online'#

新しいワーカーをフォークした後、ワーカーはオンラインメッセージで応答する必要があります。プライマリーがオンラインメッセージを受信すると、このイベントが発行されます。'fork''online'の違いは、forkはプライマリーがワーカーをフォークしたときに発行され、'online'はワーカーが実行中になったときに発行される点です。

cluster.on('online', (worker) => {
  console.log('Yay, the worker responded after it was forked');
}); 

イベント: 'setup'#

.setupPrimary()が呼び出されるたびに発行されます。

settingsオブジェクトは、.setupPrimary()が呼び出された時点のcluster.settingsオブジェクトであり、助言的なものにすぎません。なぜなら、単一のティック内で.setupPrimary()が複数回呼び出される可能性があるためです。

正確性が重要な場合は、cluster.settingsを使用してください。

cluster.disconnect([callback])#

  • callback <Function> すべてのワーカーが切断され、ハンドルが閉じられたときに呼び出されます。

cluster.workers内の各ワーカーで.disconnect()を呼び出します。

それらが切断されると、すべての内部ハンドルが閉じられ、他に待機しているイベントがなければプライマリープロセスが正常に終了できるようになります。

このメソッドはオプションのコールバック引数を取り、終了時に呼び出されます。

これはプライマリープロセスからのみ呼び出すことができます。

cluster.fork([env])#

新しいワーカープロセスを生成します。

これはプライマリープロセスからのみ呼び出すことができます。

cluster.isMaster#

安定性: 0 - 非推奨

cluster.isPrimaryの非推奨エイリアス。

cluster.isPrimary#

プロセスがプライマリーである場合はtrue。これはprocess.env.NODE_UNIQUE_IDによって決定されます。process.env.NODE_UNIQUE_IDがundefinedの場合、isPrimarytrueです。

cluster.isWorker#

プロセスがプライマリーでない場合はtrue(cluster.isPrimaryの否定です)。

cluster.schedulingPolicy#

スケジューリングポリシー。ラウンドロビン用のcluster.SCHED_RR、またはオペレーティングシステムに任せるためのcluster.SCHED_NONEのいずれかです。これはグローバルな設定であり、最初のワーカーが生成されるか、.setupPrimary()が呼び出されるかのいずれか早い方で事実上固定されます。

SCHED_RRはWindowsを除くすべてのオペレーティングシステムでのデフォルトです。Windowsは、libuvが大きなパフォーマンスヒットを伴わずにIOCPハンドルを効果的に分散できるようになるとSCHED_RRに変更されます。

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> 親のstdioに出力を送信するかどうか。デフォルト: false
    • stdio <Array> フォークされたプロセスのstdioを設定します。clusterモジュールは機能するためにIPCに依存しているため、この設定には'ipc'エントリが含まれている必要があります。このオプションが指定されると、silentを上書きします。child_process.spawn()stdioを参照してください。
    • uid <number> プロセスのユーザーIDを設定します。(setuid(2)を参照。)
    • gid <number> プロセスのグループIDを設定します。(setgid(2)を参照。)
    • inspectPort <number> | <Function> ワーカーのインスペクターポートを設定します。これは数値、または引数を取らずに数値を返す関数にすることができます。デフォルトでは、各ワーカーはプライマリーのprocess.debugPortからインクリメントされた独自のポートを取得します。
    • windowsHide <boolean> Windowsシステムで通常作成されるフォークされたプロセスのコンソールウィンドウを非表示にします。デフォルト: false

.setupPrimary()(または.fork())を呼び出した後、このsettingsオブジェクトにはデフォルト値を含む設定が含まれます。

このオブジェクトは手動で変更または設定することを意図していません。

cluster.setupMaster([settings])#

安定性: 0 - 非推奨

.setupPrimary()の非推奨エイリアス。

cluster.setupPrimary([settings])#

setupPrimaryは、デフォルトの'fork'の動作を変更するために使用されます。一度呼び出されると、設定はcluster.settingsに存在します。

設定の変更は、将来の.fork()の呼び出しにのみ影響し、すでに実行中のワーカーには影響しません。

.setupPrimary()を介して設定できないワーカーの唯一の属性は、.fork()に渡されるenvです。

上記のデフォルトは最初の呼び出しにのみ適用されます。それ以降の呼び出しのデフォルトは、cluster.setupPrimary()が呼び出された時点での現在の値です。

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 workerconst 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#

現在のワーカーオブジェクトへの参照。プライマリープロセスでは利用できません。

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}`);
}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#

アクティブなワーカーオブジェクトをidフィールドをキーとして格納するハッシュ。これにより、すべてのワーカーを簡単にループ処理できます。プライマリープロセスでのみ利用可能です。

ワーカーは、切断され、かつ終了した後にcluster.workersから削除されます。これら2つのイベントの順序は事前に決定できません。ただし、cluster.workersリストからの削除は、最後の'disconnect'または'exit'イベントが発行される前に発生することが保証されています。

import cluster from 'node:cluster';

for (const worker of Object.values(cluster.workers)) {
  worker.send('big announcement to all workers');
}const cluster = require('node:cluster');

for (const worker of Object.values(cluster.workers)) {
  worker.send('big announcement to all workers');
}