mirror of
https://github.com/nodejs/node.git
synced 2025-05-15 19:48:12 +00:00
doc: cluster documentation cleanup and corrections
- fixed some incomprehensible wording ("event assigned to..."?) - removed undocumented and unnecessary process properties from example - corrected the docs on the default for the exec setting - described when workers are removed from cluster.workers - described addressType, which was documented as existing, but not what values it might have - spell out more clearly the limitations of setupMaster - describe disconnect in sufficient detail that why a child does or does not exit can be understood - clarify which cluster functions and events are available on process or just on the worker, as well as which are not available in children, - don't describe events as the same, when they have receive different arguments - fix misleading disconnect example: since disconnect already calls close on all servers, doing it again in the example is a no-op, not the "force close" it was claimed to be - document the error event, not catching it will kill your node - describe suicide better, it is important, and a bit unintuitive (process.exit() is not suicide?) - use worker consistently throughout, instead of child.
This commit is contained in:
parent
ed186c971c
commit
2e16037201
@ -6,7 +6,7 @@ A single instance of Node runs in a single thread. To take advantage of
|
|||||||
multi-core systems the user will sometimes want to launch a cluster of Node
|
multi-core systems the user will sometimes want to launch a cluster of Node
|
||||||
processes to handle the load.
|
processes to handle the load.
|
||||||
|
|
||||||
The cluster module allows you to easily create a network of processes that
|
The cluster module allows you to easily create child processes that
|
||||||
all share server ports.
|
all share server ports.
|
||||||
|
|
||||||
var cluster = require('cluster');
|
var cluster = require('cluster');
|
||||||
@ -58,7 +58,7 @@ arguments and passes the request to the master process. If the master
|
|||||||
process already has a listening server matching the worker's
|
process already has a listening server matching the worker's
|
||||||
requirements, then it passes the handle to the worker. If it does not
|
requirements, then it passes the handle to the worker. If it does not
|
||||||
already have a listening server matching that requirement, then it will
|
already have a listening server matching that requirement, then it will
|
||||||
create one, and pass the handle to the child.
|
create one, and pass the handle to the worker.
|
||||||
|
|
||||||
This causes potentially surprising behavior in three edge cases:
|
This causes potentially surprising behavior in three edge cases:
|
||||||
|
|
||||||
@ -94,13 +94,18 @@ the worker pool for your application's needs.
|
|||||||
## cluster.settings
|
## cluster.settings
|
||||||
|
|
||||||
* {Object}
|
* {Object}
|
||||||
* `exec` {String} file path to worker file. (Default=`__filename`)
|
* `exec` {String} file path to worker file. (Default=`process.argv[1]`)
|
||||||
* `args` {Array} string arguments passed to worker.
|
* `args` {Array} string arguments passed to worker.
|
||||||
(Default=`process.argv.slice(2)`)
|
(Default=`process.argv.slice(2)`)
|
||||||
* `silent` {Boolean} whether or not to send output to parent's stdio.
|
* `silent` {Boolean} whether or not to send output to parent's stdio.
|
||||||
(Default=`false`)
|
(Default=`false`)
|
||||||
|
|
||||||
All settings set by the `.setupMaster` is stored in this settings object.
|
After calling `.setupMaster()` (or `.fork()`) this settings object will contain
|
||||||
|
the settings, including the default values.
|
||||||
|
|
||||||
|
It is effectively frozen after being set, because `.setupMaster()` can
|
||||||
|
only be called once.
|
||||||
|
|
||||||
This object is not supposed to be changed or set manually, by you.
|
This object is not supposed to be changed or set manually, by you.
|
||||||
|
|
||||||
## cluster.isMaster
|
## cluster.isMaster
|
||||||
@ -115,9 +120,7 @@ undefined, then `isMaster` is `true`.
|
|||||||
|
|
||||||
* {Boolean}
|
* {Boolean}
|
||||||
|
|
||||||
This boolean flag is true if the process is a worker forked from a master.
|
True if the process is not a master (it is the negation of `cluster.isMaster`).
|
||||||
If the `process.env.NODE_UNIQUE_ID` is set to a value, then
|
|
||||||
`isWorker` is `true`.
|
|
||||||
|
|
||||||
## Event: 'fork'
|
## Event: 'fork'
|
||||||
|
|
||||||
@ -146,11 +149,10 @@ This can be used to log worker activity, and create you own timeout.
|
|||||||
|
|
||||||
* `worker` {Worker object}
|
* `worker` {Worker object}
|
||||||
|
|
||||||
After forking a new worker, the worker should respond with a online message.
|
After forking a new worker, the worker should respond with an online message.
|
||||||
When the master receives a online message it will emit such event.
|
When the master receives an online message it will emit this event.
|
||||||
The difference between 'fork' and 'online' is that fork is emitted when the
|
The difference between 'fork' and 'online' is that fork is emitted when the
|
||||||
master tries to fork a worker, and 'online' is emitted when the worker is
|
master forks a worker, and 'online' is emitted when the worker is running.
|
||||||
being executed.
|
|
||||||
|
|
||||||
cluster.on('online', function(worker) {
|
cluster.on('online', function(worker) {
|
||||||
console.log("Yay, the worker responded after it was forked");
|
console.log("Yay, the worker responded after it was forked");
|
||||||
@ -161,9 +163,8 @@ being executed.
|
|||||||
* `worker` {Worker object}
|
* `worker` {Worker object}
|
||||||
* `address` {Object}
|
* `address` {Object}
|
||||||
|
|
||||||
When calling `listen()` from a worker, a 'listening' event is automatically assigned
|
After calling `listen()` from a worker, when the 'listening' event is emitted on
|
||||||
to the server instance. When the server is listening a message is send to the master
|
the server, a listening event will also be emitted on `cluster` in the master.
|
||||||
where the 'listening' event is emitted.
|
|
||||||
|
|
||||||
The event handler is executed with two arguments, the `worker` contains the worker
|
The event handler is executed with two arguments, the `worker` contains the worker
|
||||||
object and the `address` object contains the following connection properties:
|
object and the `address` object contains the following connection properties:
|
||||||
@ -174,18 +175,24 @@ on more than one address.
|
|||||||
console.log("A worker is now connected to " + address.address + ":" + address.port);
|
console.log("A worker is now connected to " + address.address + ":" + address.port);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
The `addressType` is one of:
|
||||||
|
|
||||||
|
* `4' (TCPv4)
|
||||||
|
* `6` (TCPv6)
|
||||||
|
* `-1` (unix domain socket)
|
||||||
|
* `"udp4"` or `"udp6"` (UDP v4 or v6)
|
||||||
|
|
||||||
## Event: 'disconnect'
|
## Event: 'disconnect'
|
||||||
|
|
||||||
* `worker` {Worker object}
|
* `worker` {Worker object}
|
||||||
|
|
||||||
When a workers IPC channel has disconnected this event is emitted.
|
Emitted after the worker IPC channel has disconnected. This can occur when a
|
||||||
This will happen when the worker dies, usually after calling
|
worker exits gracefully, is killed, or is disconnected manually (such as with
|
||||||
`.kill()`.
|
worker.disconnect()).
|
||||||
|
|
||||||
When calling `.disconnect()`, there may be a delay between the
|
There may be a delay between the `disconnect` and `exit` events. These events
|
||||||
`disconnect` and `exit` events. This event can be used to detect if
|
can be used to detect if the process is stuck in a cleanup or if there are
|
||||||
the process is stuck in a cleanup or if there are long-living
|
long-living connections.
|
||||||
connections.
|
|
||||||
|
|
||||||
cluster.on('disconnect', function(worker) {
|
cluster.on('disconnect', function(worker) {
|
||||||
console.log('The worker #' + worker.id + ' has disconnected');
|
console.log('The worker #' + worker.id + ' has disconnected');
|
||||||
@ -199,33 +206,42 @@ connections.
|
|||||||
the process to be killed.
|
the process to be killed.
|
||||||
|
|
||||||
When any of the workers die the cluster module will emit the 'exit' event.
|
When any of the workers die the cluster module will emit the 'exit' event.
|
||||||
This can be used to restart the worker by calling `fork()` again.
|
|
||||||
|
This can be used to restart the worker by calling `.fork()` again.
|
||||||
|
|
||||||
cluster.on('exit', function(worker, code, signal) {
|
cluster.on('exit', function(worker, code, signal) {
|
||||||
var exitCode = worker.process.exitCode;
|
console.log('worker %d died (%s). restarting...',
|
||||||
console.log('worker ' + worker.process.pid + ' died ('+exitCode+'). restarting...');
|
worker.process.pid, signal || code);
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
See [child_process event: 'exit'](child_process.html#child_process_event_exit).
|
||||||
|
|
||||||
## Event: 'setup'
|
## Event: 'setup'
|
||||||
|
|
||||||
* `worker` {Worker object}
|
Emitted the first time that `.setupMaster()` is called.
|
||||||
|
|
||||||
When the `.setupMaster()` function has been executed this event emits.
|
|
||||||
If `.setupMaster()` was not executed before `fork()` this function will
|
|
||||||
call `.setupMaster()` with no arguments.
|
|
||||||
|
|
||||||
## cluster.setupMaster([settings])
|
## cluster.setupMaster([settings])
|
||||||
|
|
||||||
* `settings` {Object}
|
* `settings` {Object}
|
||||||
* `exec` {String} file path to worker file. (Default=`__filename`)
|
* `exec` {String} file path to worker file. (Default=`process.argv[1]`)
|
||||||
* `args` {Array} string arguments passed to worker.
|
* `args` {Array} string arguments passed to worker.
|
||||||
(Default=`process.argv.slice(2)`)
|
(Default=`process.argv.slice(2)`)
|
||||||
* `silent` {Boolean} whether or not to send output to parent's stdio.
|
* `silent` {Boolean} whether or not to send output to parent's stdio.
|
||||||
(Default=`false`)
|
(Default=`false`)
|
||||||
|
|
||||||
`setupMaster` is used to change the default 'fork' behavior. The new settings
|
`setupMaster` is used to change the default 'fork' behavior. Once called,
|
||||||
are effective immediately and permanently, they cannot be changed later on.
|
the settings will be present in `cluster.settings`.
|
||||||
|
|
||||||
|
Note that:
|
||||||
|
|
||||||
|
* Only the first call to `.setupMaster()` has any effect, subsequent calls are
|
||||||
|
ignored
|
||||||
|
* That because of the above, the *only* attribute of a worker that may be
|
||||||
|
customized per-worker is the `env` passed to `.fork()`
|
||||||
|
* `.fork()` calls `.setupMaster()` internally to establish the defaults, so to
|
||||||
|
have any effect, `.setupMaster()` must be called *before* any calls to
|
||||||
|
`.fork()`
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -237,23 +253,31 @@ Example:
|
|||||||
});
|
});
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
|
|
||||||
|
This can only be called from the master process.
|
||||||
|
|
||||||
## cluster.fork([env])
|
## cluster.fork([env])
|
||||||
|
|
||||||
* `env` {Object} Key/value pairs to add to child process environment.
|
* `env` {Object} Key/value pairs to add to worker process environment.
|
||||||
* return {Worker object}
|
* return {Worker object}
|
||||||
|
|
||||||
Spawn a new worker process. This can only be called from the master process.
|
Spawn a new worker process.
|
||||||
|
|
||||||
|
This can only be called from the master process.
|
||||||
|
|
||||||
## cluster.disconnect([callback])
|
## cluster.disconnect([callback])
|
||||||
|
|
||||||
* `callback` {Function} called when all workers are disconnected and handlers are closed
|
* `callback` {Function} called when all workers are disconnected and handles are
|
||||||
|
closed
|
||||||
|
|
||||||
When calling this method, all workers will commit a graceful suicide. When they are
|
Calls `.disconnect()` on each worker in `cluster.workers`.
|
||||||
disconnected all internal handlers will be closed, allowing the master process to
|
|
||||||
die graceful if no other event is waiting.
|
When they are disconnected all internal handles will be closed, allowing the
|
||||||
|
master process to die gracefully if no other event is waiting.
|
||||||
|
|
||||||
The method takes an optional callback argument which will be called when finished.
|
The method takes an optional callback argument which will be called when finished.
|
||||||
|
|
||||||
|
This can only be called from the master process.
|
||||||
|
|
||||||
## cluster.worker
|
## cluster.worker
|
||||||
|
|
||||||
* {Object}
|
* {Object}
|
||||||
@ -278,6 +302,9 @@ A hash that stores the active worker objects, keyed by `id` field. Makes it
|
|||||||
easy to loop through all the workers. It is only available in the master
|
easy to loop through all the workers. It is only available in the master
|
||||||
process.
|
process.
|
||||||
|
|
||||||
|
A worker is removed from cluster.workers just before the `'disconnect'` or
|
||||||
|
`'exit'` event is emitted.
|
||||||
|
|
||||||
// Go through all workers
|
// Go through all workers
|
||||||
function eachWorker(callback) {
|
function eachWorker(callback) {
|
||||||
for (var id in cluster.workers) {
|
for (var id in cluster.workers) {
|
||||||
@ -316,17 +343,33 @@ cluster.workers
|
|||||||
* {ChildProcess object}
|
* {ChildProcess object}
|
||||||
|
|
||||||
All workers are created using `child_process.fork()`, the returned object
|
All workers are created using `child_process.fork()`, the returned object
|
||||||
from this function is stored in process.
|
from this function is stored as `.process`. In a worker, the global `process`
|
||||||
|
is stored.
|
||||||
|
|
||||||
See: [Child Process module](child_process.html)
|
See: [Child Process module](
|
||||||
|
child_process.html#child_process_child_process_fork_modulepath_args_options)
|
||||||
|
|
||||||
|
Note that workers will call `process.exit(0)` if the `'disconnect'` event occurs
|
||||||
|
on `process` and `.suicide` is not `true`. This protects against accidental
|
||||||
|
disconnection.
|
||||||
|
|
||||||
### worker.suicide
|
### worker.suicide
|
||||||
|
|
||||||
* {Boolean}
|
* {Boolean}
|
||||||
|
|
||||||
This property is a boolean. It is set when a worker dies after calling
|
Set by calling `.kill()` or `.disconnect()`, until then it is `undefined`.
|
||||||
`.kill()` or immediately after calling the `.disconnect()` method.
|
|
||||||
Until then it is `undefined`.
|
The boolean `worker.suicide` lets you distinguish between voluntary and accidental
|
||||||
|
exit, the master may choose not to respawn a worker based on this value.
|
||||||
|
|
||||||
|
cluster.on('exit', function(worker, code, signal) {
|
||||||
|
if (worker.suicide === true) {
|
||||||
|
console.log('Oh, it was just suicide\' – no need to worry').
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// kill worker
|
||||||
|
worker.kill();
|
||||||
|
|
||||||
### worker.send(message, [sendHandle])
|
### worker.send(message, [sendHandle])
|
||||||
|
|
||||||
@ -335,8 +378,9 @@ Until then it is `undefined`.
|
|||||||
|
|
||||||
This function is equal to the send methods provided by
|
This function is equal to the send methods provided by
|
||||||
`child_process.fork()`. In the master you should use this function to
|
`child_process.fork()`. In the master you should use this function to
|
||||||
send a message to a specific worker. However in a worker you can also use
|
send a message to a specific worker.
|
||||||
`process.send(message)`, since this is the same function.
|
|
||||||
|
In a worker you can also use `process.send(message)`, it is the same function.
|
||||||
|
|
||||||
This example will echo back all messages from the master:
|
This example will echo back all messages from the master:
|
||||||
|
|
||||||
@ -355,44 +399,54 @@ This example will echo back all messages from the master:
|
|||||||
* `signal` {String} Name of the kill signal to send to the worker
|
* `signal` {String} Name of the kill signal to send to the worker
|
||||||
process.
|
process.
|
||||||
|
|
||||||
This function will kill the worker, and inform the master to not spawn a
|
This function will kill the worker. In the master, it does this by disconnecting
|
||||||
new worker. The boolean `suicide` lets you distinguish between voluntary
|
the `worker.process`, and once disconnected, killing with `signal`. In the
|
||||||
and accidental exit.
|
worker, it does it by disconnecting the channel, and then exiting with code `0`.
|
||||||
|
|
||||||
cluster.on('exit', function(worker, code, signal) {
|
Causes `.suicide` to be set.
|
||||||
if (worker.suicide === true) {
|
|
||||||
console.log('Oh, it was just suicide\' – no need to worry').
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// kill worker
|
This method is aliased as `worker.destroy()` for backwards compatibility.
|
||||||
worker.kill();
|
|
||||||
|
|
||||||
This method is aliased as `worker.destroy()` for backwards
|
Note that in a worker, `process.kill()` exists, but it is not this function,
|
||||||
compatibility.
|
it is [kill](process.html#process_process_kill_pid_signal).
|
||||||
|
|
||||||
### worker.disconnect()
|
### worker.disconnect()
|
||||||
|
|
||||||
When calling this function the worker will no longer accept new connections, but
|
In a worker, this function will close all servers, wait for the 'close' event on
|
||||||
they will be handled by any other listening worker. Existing connection will be
|
those servers, and then disconnect the IPC channel.
|
||||||
allowed to exit as usual. When no more connections exist, the IPC channel to the worker
|
|
||||||
will close allowing it to die graceful. When the IPC channel is closed the `disconnect`
|
|
||||||
event will emit, this is then followed by the `exit` event, there is emitted when
|
|
||||||
the worker finally die.
|
|
||||||
|
|
||||||
Because there might be long living connections, it is useful to implement a timeout.
|
In the master, an internal message is sent to the worker causing it to call
|
||||||
This example ask the worker to disconnect and after 2 seconds it will destroy the
|
`.disconnect()` on itself.
|
||||||
server. An alternative would be to execute `worker.kill()` after 2 seconds, but
|
|
||||||
that would normally not allow the worker to do any cleanup if needed.
|
Causes `.suicide` to be set.
|
||||||
|
|
||||||
|
Note that 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()](net.html#net_event_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.
|
||||||
|
|
||||||
|
Note that in a worker, `process.disconnect` exists, but it is not this function,
|
||||||
|
it is [disconnect](child_process.html#child_process_child_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.isMaster) {
|
if (cluster.isMaster) {
|
||||||
var worker = cluster.fork();
|
var worker = cluster.fork();
|
||||||
var timeout;
|
var timeout;
|
||||||
|
|
||||||
worker.on('listening', function(address) {
|
worker.on('listening', function(address) {
|
||||||
|
worker.send('shutdown');
|
||||||
worker.disconnect();
|
worker.disconnect();
|
||||||
timeout = setTimeout(function() {
|
timeout = setTimeout(function() {
|
||||||
worker.send('force kill');
|
worker.kill();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -403,18 +457,14 @@ that would normally not allow the worker to do any cleanup if needed.
|
|||||||
} else if (cluster.isWorker) {
|
} else if (cluster.isWorker) {
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var server = net.createServer(function(socket) {
|
var server = net.createServer(function(socket) {
|
||||||
// connection never end
|
// connections never end
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(8000);
|
server.listen(8000);
|
||||||
|
|
||||||
server.on('close', function() {
|
|
||||||
// cleanup
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on('message', function(msg) {
|
process.on('message', function(msg) {
|
||||||
if (msg === 'force kill') {
|
if(msg === 'shutdown') {
|
||||||
server.close();
|
// initiate graceful close of any connections to server
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -424,8 +474,8 @@ that would normally not allow the worker to do any cleanup if needed.
|
|||||||
* `message` {Object}
|
* `message` {Object}
|
||||||
|
|
||||||
This event is the same as the one provided by `child_process.fork()`.
|
This event is the same as the one provided by `child_process.fork()`.
|
||||||
In the master you should use this event, however in a worker you can also use
|
|
||||||
`process.on('message')`
|
In a worker you can also use `process.on('message')`.
|
||||||
|
|
||||||
As an example, here is a cluster that keeps count of the number of requests
|
As an example, here is a cluster that keeps count of the number of requests
|
||||||
in the master process using the message system:
|
in the master process using the message system:
|
||||||
@ -472,28 +522,29 @@ in the master process using the message system:
|
|||||||
|
|
||||||
### Event: 'online'
|
### Event: 'online'
|
||||||
|
|
||||||
Same as the `cluster.on('online')` event, but emits only when the state change
|
Similar to the `cluster.on('online')` event, but specific to this worker.
|
||||||
on the specified worker.
|
|
||||||
|
|
||||||
cluster.fork().on('online', function() {
|
cluster.fork().on('online', function() {
|
||||||
// Worker is online
|
// Worker is online
|
||||||
});
|
});
|
||||||
|
|
||||||
|
It is not emitted in the worker.
|
||||||
|
|
||||||
### Event: 'listening'
|
### Event: 'listening'
|
||||||
|
|
||||||
* `address` {Object}
|
* `address` {Object}
|
||||||
|
|
||||||
Same as the `cluster.on('listening')` event, but emits only when the state change
|
Similar to the `cluster.on('listening')` event, but specific to this worker.
|
||||||
on the specified worker.
|
|
||||||
|
|
||||||
cluster.fork().on('listening', function(address) {
|
cluster.fork().on('listening', function(address) {
|
||||||
// Worker is listening
|
// Worker is listening
|
||||||
});
|
});
|
||||||
|
|
||||||
|
It is not emitted in the worker.
|
||||||
|
|
||||||
### Event: 'disconnect'
|
### Event: 'disconnect'
|
||||||
|
|
||||||
Same as the `cluster.on('disconnect')` event, but emits only when the state change
|
Similar to the `cluster.on('disconnect')` event, but specfic to this worker.
|
||||||
on the specified worker.
|
|
||||||
|
|
||||||
cluster.fork().on('disconnect', function() {
|
cluster.fork().on('disconnect', function() {
|
||||||
// Worker has disconnected
|
// Worker has disconnected
|
||||||
@ -505,8 +556,7 @@ on the specified worker.
|
|||||||
* `signal` {String} the name of the signal (eg. `'SIGHUP'`) that caused
|
* `signal` {String} the name of the signal (eg. `'SIGHUP'`) that caused
|
||||||
the process to be killed.
|
the process to be killed.
|
||||||
|
|
||||||
Emitted by the individual worker instance, when the underlying child process
|
Similar to the `cluster.on('exit')` event, but specific to this worker.
|
||||||
is terminated. See [child_process event: 'exit'](child_process.html#child_process_event_exit).
|
|
||||||
|
|
||||||
var worker = cluster.fork();
|
var worker = cluster.fork();
|
||||||
worker.on('exit', function(code, signal) {
|
worker.on('exit', function(code, signal) {
|
||||||
@ -518,3 +568,9 @@ is terminated. See [child_process event: 'exit'](child_process.html#child_proce
|
|||||||
console.log("worker success!");
|
console.log("worker success!");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
### Event: 'error'
|
||||||
|
|
||||||
|
This event is the same as the one provided by `child_process.fork()`.
|
||||||
|
|
||||||
|
In a worker you can also use `process.on('error')`.
|
||||||
|
Loading…
Reference in New Issue
Block a user