Cluster | Node.js v22.23.2 Documentation
https://nodejs.org/docs/latest-v22.x/api/cluster.html • 93 KB fetched
Open original page
Cluster | Node.js v22.23.2 Documentation
Skip to content
Node.js
* About this documentation
* Usage and example
* Assertion testing
* Asynchronous context tracking
* Async hooks
* Buffer
* C++ addons
* C/C++ addons with Node-API
* C++ embedder API
* Child processes
* Cluster
* Command-line options
* Console
* Crypto
* Debugger
* Deprecated APIs
* Diagnostics Channel
* DNS
* Domain
* Environment Variables
* Errors
* Events
* File system
* Globals
* HTTP
* HTTP/2
* HTTPS
* Inspector
* Internationalization
* Modules: CommonJS modules
* Modules: ECMAScript modules
* Modules: node:module API
* Modules: Packages
* Modules: TypeScript
* Net
* OS
* Path
* Performance hooks
* Permissions
* Process
* Punycode
* Query strings
* Readline
* REPL
* Report
* Single executable applications
* SQLite
* Stream
* String decoder
* Test runner
* Timers
* TLS/SSL
* Trace events
* TTY
* UDP/datagram
* URL
* Utilities
* V8
* VM
* WASI
* Web Crypto API
* Web Streams API
* Worker threads
* Zlib
* Code repository and issue tracker
Node.js v22.23.2 documentation
* Node.js v22.23.2
*
Table of contents
* Cluster
* How it works
* Class: Worker
* Event: 'disconnect'
* Event: 'error'
* Event: 'exit'
* Event: 'listening'
* Event: 'message'
* Event: 'online'
* worker.disconnect()
* worker.exitedAfterDisconnect
* worker.id
* worker.isConnected()
* worker.isDead()
* worker.kill([signal])
* worker.process
* worker.send(message[, sendHandle[, options]][, callback])
* Event: 'disconnect'
* Event: 'exit'
* Event: 'fork'
* Event: 'listening'
* Event: 'message'
* Event: 'online'
* Event: 'setup'
* cluster.disconnect([callback])
* cluster.fork([env])
* cluster.isMaster
* cluster.isPrimary
* cluster.isWorker
* cluster.schedulingPolicy
* cluster.settings
* cluster.setupMaster([settings])
* cluster.setupPrimary([settings])
* cluster.worker
* cluster.workers
*
Index
* About this documentation
* Usage and example
*
Index
* Assertion testing
* Asynchronous context tracking
* Async hooks
* Buffer
* C++ addons
* C/C++ addons with Node-API
* C++ embedder API
* Child processes
* Cluster
* Command-line options
* Console
* Crypto
* Debugger
* Deprecated APIs
* Diagnostics Channel
* DNS
* Domain
* Environment Variables
* Errors
* Events
* File system
* Globals
* HTTP
* HTTP/2
* HTTPS
* Inspector
* Internationalization
* Modules: CommonJS modules
* Modules: ECMAScript modules
* Modules: node:module API
* Modules: Packages
* Modules: TypeScript
* Net
* OS
* Path
* Performance hooks
* Permissions
* Process
* Punycode
* Query strings
* Readline
* REPL
* Report
* Single executable applications
* SQLite
* Stream
* String decoder
* Test runner
* Timers
* TLS/SSL
* Trace events
* TTY
* UDP/datagram
* URL
* Utilities
* V8
* VM
* WASI
* Web Crypto API
* Web Streams API
* Worker threads
* Zlib
* Code repository and issue tracker
*
Other versions
* 26.x
* 25.x
* 24.x LTS
* 23.x
* 22.x LTS
* 21.x
* 20.x
* 19.x
* 18.x
* 17.x
* 16.x
* 15.x
* 14.x
* 13.x
* 12.x
* 11.x
* 10.x
* 9.x
* 8.x
* 7.x
* 6.x
* 5.x
* 4.x
* 0.12.x
* 0.10.x
*
Options
*
View on single page
*
View as JSON
* Edit on GitHub
Table of contents
* Cluster
* How it works
* Class: Worker
* Event: 'disconnect'
* Event: 'error'
* Event: 'exit'
* Event: 'listening'
* Event: 'message'
* Event: 'online'
* worker.disconnect()
* worker.exitedAfterDisconnect
* worker.id
* worker.isConnected()
* worker.isDead()
* worker.kill([signal])
* worker.process
* worker.send(message[, sendHandle[, options]][, callback])
* Event: 'disconnect'
* Event: 'exit'
* Event: 'fork'
* Event: 'listening'
* Event: 'message'
* Event: 'online'
* Event: 'setup'
* cluster.disconnect([callback])
* cluster.fork([env])
* cluster.isMaster
* cluster.isPrimary
* cluster.isWorker
* cluster.schedulingPolicy
* cluster.settings
* cluster.setupMaster([settings])
* cluster.setupPrimary([settings])
* cluster.worker
* cluster.workers
Cluster #
Stability: 2 - Stable
Source Code: lib/cluster.js
Clusters of Node.js processes can be used to run multiple instances of Node.js
that can distribute workloads among their application threads. When process
isolation is not needed, use the worker_threads module instead, which
allows running multiple application threads within a single Node.js instance.
The cluster module allows easy creation of child processes that all share
server ports.
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` );
} copy
Running Node.js will now share port 8000 between the workers:
$ node server.js
Primary 3596 is running
Worker 4324 started
Worker 4520 started
Worker 6056 started
Worker 5644 started copy
On Windows, it is not yet possible to set up a named pipe server in a worker.
How it works #
The worker processes are spawned using the child_process.fork() method,
so that they can communicate with the parent via IPC and pass server
handles back and forth.
The cluster module supports two methods of distributing incoming
connections.
The first one (and the default one on all platforms except Windows)
is the round-robin approach, where the primary process listens on a
port, accepts new connections and distributes them across the workers
in a round-robin fashion, with some built-in smarts to avoid
overloading a worker process.
The second approach is where the primary process creates the listen
socket and sends it to interested workers. The workers then accept
incoming connections directly.
The second approach should, in theory, give the best performance.
In practice however, distribution tends to be very unbalanced due
to operating system scheduler vagaries. Loads have been observed
where over 70% of all connections ended up in just two processes,
out of a total of eight.
Because server.listen() hands off most of the work to the primary
process, there are three cases where the behavior between a normal
Node.js process and a cluster worker differs:
* server.listen({fd: 7}) Because the message is passed to the primary,
file descriptor 7 in the parent will be listened on, and the
handle passed to the worker, rather than listening to the worker's
idea of what the number 7 file descriptor references.
* server.listen(handle) Listening on handles explicitly will cause
the worker to use the supplied handle, rather than talk to the primary
process.
* server.listen(0) Normally, this will cause servers to listen on a
random port. However, in a cluster, each worker will receive the
same "random" port each time they do listen(0) . In essence, the
port is random the first time, but predictable thereafter. To listen
on a unique port, generate a port number based on the cluster worker ID.
Node.js does not provide routing logic. It is therefore important to design an
application such that it does not rely too heavily on in-memory data objects for
things like sessions and login.
Because workers are all separate processes, they can be killed or
re-spawned depending on a program's needs, without affecting other
workers. As long as there are some workers still alive, the server will
continue to accept connections. If no workers are alive, existing connections
will be dropped and new connections will be refused. Node.js does not
automatically manage the number of workers, however. It is the application's
responsibility to manage the worker pool based on its own needs.
Although a primary use case for the node:cluster module is networking, it can
also be used for other use cases requiring worker processes.
Class: Worker #
Added in: v0.7.0
* Extends: <EventEmitter>
A Worker object contains all public information and method about a worker.
In the primary it can be obtained using cluster.workers . In a worker
it can be obtained using cluster.worker .
Event: 'disconnect' #
Added in: v0.7.7
Similar to the cluster.on('disconnect') event, but specific to this worker.
cluster. fork (). on ( 'disconnect' , () => {
// Worker has disconnected
}); copy
Event: 'error' #
Added in: v0.7.3
This event is the same as the one provided by child_process.fork() .
Within a worker, process.on('error') may also be used.
Event: 'exit' #
Added in: v0.11.2
* code <number> The exit code, if it exited normally.
* signal <string> The name of the signal (e.g. 'SIGHUP' ) that caused
the process to be killed.
Similar to the cluster.on('exit') event, but specific to this worker.
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!' );
}
});
} copy
Event: 'listening' #
Added in: v0.7.0
* address <Object>
Similar to the cluster.on('listening') event, but specific to this worker.
cluster. fork (). on ( 'listening' , ( address ) => {
// Worker is listening
}); cluster. fork (). on ( 'listening' , ( address ) => {
// Worker is listening
}); copy
It is not emitted in the worker.
Event: 'message' #
Added in: v0.7.0
* message <Object>
* handle <undefined> | <Object>
Similar to the 'message' event of cluster , but specific to this worker.
Within a worker, process.on('message') may also be used.
See process event: 'message' .
Here is an example using the message system. It keeps a count in the primary
process of the number of HTTP requests received by the workers:
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 );
} copy
Event: 'online' #
Added in: v0.7.0
Similar to the cluster.on('online') event, but specific to this worker.
cluster. fork (). on ( 'online' , () => {
// Worker is online
}); copy
It is not emitted in the worker.
worker.disconnect() #
History
Version Changes
v7.3.0
This method now returns a reference to worker .
v0.7.7
Added in: v0.7.7
* Returns: <cluster.Worker> A reference to worker .
In a worker, this function will close all servers, wait for the 'close' event
on those servers, and then disconnect the IPC channel.
In the primary, an internal message is sent to the worker causing it to call
.disconnect() on itself.
Causes .exitedAfterDisconnect to be set.
After a server is closed, it will no longer accept new connections,
but connections may be accepted by any other listening worker. Existing
connections will be allowed to close as usual. When no more connections exist,
see server.close() , the IPC channel to the worker will close allowing it
to die gracefully.
The above applies only to server connections, client connections are not
automatically closed by workers, and disconnect does not wait for them to close
before exiting.
In a worker, process.disconnect exists, but it is not this function;
it is disconnect() .
Because long living server connections may block workers from disconnecting, it
may be useful to send a message, so application specific actions may be taken to
close them. It also may be useful to implement a timeout, killing a worker if
the 'disconnect' event has not been emitted after some time.
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 #
Added in: v6.0.0
* Type: <boolean>
This property is true if the worker exited due to .disconnect() .
If the worker exited any other way, it is false . If the
worker has not exited, it is undefined .
The boolean worker.exitedAfterDisconnect allows distinguishing between
voluntary and accidental exit, the primary may choose not to respawn a worker
based on this value.
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 #
Added in: v0.8.0
* Type: <integer>
Each new worker is given its own unique id, this id is stored in the
id .
While a worker is alive, this is the key that indexes it in
cluster.workers .
worker.isConnected() #
Added in: v0.11.14
This function returns true if the worker is connected to its primary via its
IPC channel, false otherwise. A worker is connected to its primary after it
has been created. It is disconnected after the 'disconnect' event is emitted.
worker.isDead() #
Added in: v0.11.14
This function returns true if the worker's process has terminated (either
because of exiting or being signaled). Otherwise, it returns 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 ) => {
c
Links found on this page
- Skip to content [direct]
- Node.js [direct]
- About this documentation [direct]
- Usage and example [direct]
- Assertion testing [direct]
- Asynchronous context tracking [direct]
- Async hooks [direct]
- Buffer [direct]
- C++ addons [direct]
- C/C++ addons with Node-API [direct]
- C++ embedder API [direct]
- Child processes [direct]
- Command-line options [direct]
- Console [direct]
- Crypto [direct]
- Debugger [direct]
- Deprecated APIs [direct]
- Diagnostics Channel [direct]
- DNS [direct]
- Domain [direct]
- Environment Variables [direct]
- Errors [direct]
- Events [direct]
- File system [direct]
- Globals [direct]
- HTTP [direct]
- HTTP/2 [direct]
- HTTPS [direct]
- Inspector [direct]
- Internationalization [direct]
- Modules: CommonJS modules [direct]
- Modules: ECMAScript modules [direct]
- Modules: node:module API [direct]
- Modules: Packages [direct]
- Modules: TypeScript [direct]
- Net [direct]
- OS [direct]
- Path [direct]
- Performance hooks [direct]
- Permissions [direct]
- Process [direct]
- Punycode [direct]
- Query strings [direct]
- Readline [direct]
- REPL [direct]
- Report [direct]
- Single executable applications [direct]
- SQLite [direct]
- Stream [direct]
- String decoder [direct]
- Test runner [direct]
- Timers [direct]
- TLS/SSL [direct]
- Trace events [direct]
- TTY [direct]
- UDP/datagram [direct]
- URL [direct]
- Utilities [direct]
- V8 [direct]
- VM [direct]
- WASI [direct]
- Web Crypto API [direct]
- Web Streams API [direct]
- Worker threads [direct]
- Zlib [direct]
- Code repository and issue tracker [direct]
- Index [direct]
- 26.x [direct]
- 25.x [direct]
- 24.x LTS [direct]
- 23.x [direct]
- 21.x [direct]
- 20.x [direct]
- 19.x [direct]
- 18.x [direct]
- 17.x [direct]
- 16.x [direct]
- 15.x [direct]
- 14.x [direct]
- 13.x [direct]