In Chapter 4, “Using Events, Listeners, Timers, and Callbacks in Node.js,” you learned that Node.js applications run on a single thread rather than multiple threads. Using the single thread for application processing makes Node.js processes more efficient and faster. But most servers have multiple processors, and you can scale your Node.js applications by taking advantage of them. Node.js allows you to fork work from the main application to separate processes that can then be processed in parallel with each other and the main application.
To facilitate using multiple processes Node.js provides three specific modules. The process
module provides access to the running processes. The child_process
module provides the ability to create child processes and communicate with them. The cluster
module implements clustered servers that share the same port, thus allowing multiple requests to be handled simultaneously.
The process
module is a global object that can be accessed from your Node.js applications without the need to use a require()
. This object gives you access to the running processes as well as information about the underlying hardware architecture.
The process
module provides access to the standard I/O pipes for the process stdin
, stdout
, and stderr
. stdin
is the standard input pipe for the process, which is typically the console. You can read input from the console using the following code:
process.stdin.on('data', function(data){ console.log("Console Input: " + data); });
When you type in data to the console and press Enter, the data is written back out. For example:
some data Console Input: some data
The stdout
and stderr
attributes of the process
module are Writable
streams that can be treated accordingly.
A great feature of the process
module is that it allows you to register listeners to handle signals sent to the process from the OS. This is helpful when you need to perform certain actions, such as clean up before a process is stopped or terminated. Table 9.1 lists the process events that you can add listeners for.
To register for a process signal, simply use the on(event, callback)
method. For example, to register an event handler for the SIGBREAK
event, you would use the following code:
process.on('SIGBREAK', function(){ console.log("Got a SIGBREAK"); });
Table 9.1 Events that can be sent to Node.js processes
Event |
Description |
|
Emitted when the Node.js debugger is started. You can add a listener; however, you cannot stop the debugger from starting. |
|
Emitted when the process tries to write to a pipe without a process connected on the other end. |
|
Emitted on Windows when the console window is closed, and on other platforms under various similar conditions. Note: Windows terminates Node.js about 10 seconds after sending this event. |
|
Emitted when a request is made to terminate the process. This is not supported on Windows. |
|
Emitted when a Break is sent to the process. For example, when Ctrl+C is pressed. |
|
Emitted on Windows when Ctrl+Break is pressed. |
|
Emitted when the console has been resized. On Windows, this is emitted only when you write to the console, when the cursor is being moved, or when a readable TTY is used in raw mode. |
|
Emitted on a process kill. Cannot have a listener installed. |
|
Emitted on a process stop. Cannot have a listener installed. |
process
ModuleThe process
module also gives you some control over the execution of processes, specifically, the ability to stop the current process, kill another process, or schedule work to run on the event queue. These methods are attached directly to the process
module. For example, to exit the current Node.js process, you would use:
process.exit(0)
Table 9.2 lists the available process control methods on the process
module.
Table 9.2 Methods that can be called on the process
module to affect process execution
Method |
Description |
|
Causes the current Node.js application to emit an |
|
Causes the current Node.js application to exit and return the specified |
|
Causes the OS to send a kill signal to the process with the specified |
|
Schedules the |
process
ModuleThe process
module provides a wealth of information about the running process and the system architecture. This information can be useful when implementing your applications. For example, the process.pid
property gives you the process ID that can then be used by your application.
Table 9.3 lists the properties and methods that you can access from the process
module and describes what they return.
Table 9.3 Methods that can be called on the process
module to gather information
Method |
Description |
|
Specifies the version of Node.js. |
|
Provides an object containing the required modules and version for this Node.js application. |
|
Contains the configuration options used to compile the current node executable. |
Contains the command arguments used to start the Node.js application. The first element is the node, and the second element is the path to the main JavaScript file. |
|
|
Specifies the absolute path where Node.js was started from. |
|
Specifies the node-specific command-line options used to start the application. |
|
Changes the current working |
|
Returns the current working directory for the process. |
|
Contains the key/value pairs specified in the environment for the process. |
|
Specifies the current process’s ID. |
|
Specifies the title of the currently running process. |
|
Specifies the processor architecture the process is running on (for example, |
|
Specifies the OS platform (for example, |
|
Describes the current memory usage of the Node.js process. You need to use the console.log(util.inspect(process.memoryUsage()));{ rss: 13946880, heapTotal: 4083456, heapUsed: 2190800 } |
|
Specifies the maximum number of events schedule by |
|
Contains the number of seconds the Node.js processor has been running. |
|
Returns a high-resolution time in a tuple |
|
On POSIX platforms, returns the numerical group ID for this process. |
|
On POSIX platforms, sets the numerical group ID for this process. |
|
On POSIX platforms, returns the numerical or string user ID for this process. |
|
On POSIX platforms, sets the numerical or string user ID for this process. |
On POSIX platforms, returns an array of group IDs. |
|
|
On POSIX platforms, sets the supplementary group IDs. Your Node.js application needs root privileges to call this method. |
|
On POSIX platforms, initializes the group access list with the information from |
To help you understand accessing information using the process
module, Listing 9.1 makes a series of calls and outputs the results to the console, as shown in Listing 9.1 Output.
Listing 9.1 process_info.js
: Accessing information about the process and system using the process
module
01 var util = require('util'); 02 console.log('Current directory: ' + process.cwd()); 03 console.log('Environment Settings: ' + JSON.stringify(process.env)); 04 console.log('Node Args: ' + process.argv); 05 console.log('Execution Path: ' + process.execPath); 06 console.log('Execution Args: ' + JSON.stringify(process.execArgv)); 07 console.log('Node Version: ' + process.version); 08 console.log('Module Versions: ' + JSON.stringify(process.versions)); 09 //console.log(process.config); 10 console.log('Process ID: ' + process.pid); 11 console.log('Process Title: ' + process.title); 12 console.log('Process Platform: ' + process.platform); 13 console.log('Process Architecture: ' + process.arch); 14 console.log('Memory Usage: ' + util.inspect(process.memoryUsage())); 15 var start = process.hrtime(); 16 setTimeout(function() { 17 var delta = process.hrtime(start); 18 console.log('High-Res timer took %d seconds and %d nanoseconds', delta[0], + delta[1]); 19 console.log('Node has been running %d seconds', process.uptime()); 20 }, 1000);
Listing 9.1 Output Accessing information about the process and system using the process
module
Current directory: C:UsersCalebTZDworkspace odecodech09 Environment Settings: Node Args: C:Program Files odejs ode.exe,C:UsersCalebTZDworkspace odecodech09process_info.js Execution Path: C:Program Files odejs ode.exe Execution Args: [] Node Version: v7.8.0 Module Versions: Node Config: Process ID: 12896 Process Title: C:Program Files odejs ode.exe Process Platform: win32 Process Architecture: x64 Memory Usage: { rss: 20054016, heapTotal: 5685248, heapUsed: 3571496, external: 8772 } High-Res timer took 1 seconds and 913430 nanoseconds Node has been running 1.123 seconds
To take advantage of multiple processors in a server with your Node.js applications, you need to farm work off to child processes. Node.js provides the child_process
module that allows you to spawn, fork, and execute work on other processes. The following sections discuss the process of executing tasks on other processes.
Keep in mind that child processes do not have direct access to the global memory in each other or the parent process. Therefore, you need to design your applications to run in parallel.
ChildProcess
ObjectThe child_process
module provides a new class called ChildProcess
that acts as a representation of the child processes that can be accessed from the parent. This allows you to control, end, and send messages to the child processes from the parent process that started them.
The process
module is a ChildProcess
object as well. This means that when you access process
from the parent module, it is the parent ChildProcess
object, but when you access process
from the child process, it is the ChildProcess
object.
The purpose of this section is to familiarize you with the ChildProcess
object so that in subsequent sections you can actually implement multiprocess Node.js applications. The best way to do that is to learn about the events, attributes, and methods of the ChildProcess
object.
Table 9.4 lists the events that can be emitted on the ChildProcess
object. You implement handlers for the events to handle when the child process terminates or sends messages back to the parent.
Table 9.4 Events that can be emitted on ChildProcess
objects
Event |
Description |
|
Emitted when a child.on('send': function(message){console.log(message}); |
|
Emitted when an error occurs in the worker. The handler receives an error object as the only parameter. |
|
Emitted when a worker process ends. The handler receives two arguments, |
|
Emitted when all the |
|
Emitted when |
Table 9.5 lists the methods that can be called on the child process. These methods allow you to terminate, disconnect, or send messages to the child process. For example, the following code can be called from the parent process to send an object to the child process:
child.send({cmd: 'command data'});
Table 9.5 Methods that can be called on ChildProcess
objects
Method |
Description |
|
Causes the OS to send a kill signal to the child process. The default signal is |
|
Sends a message to the handle. The message can be a string or an object. The optional |
|
Closes the IPC channel between the parent and child and sets the connected flag to |
Table 9.6 lists the properties that you can access on a ChildProcess
object.
Table 9.6 Properties that can be accessed on ChildProcess
objects
Property |
Description |
|
An input |
|
A standard output |
|
A standard output |
|
An ID of the process. |
|
A Boolean that is set to |
exec()
The simplest method of adding work to another process from a Node.js process is to execute a system command in a subshell using the exec()
function. The exec()
function can execute just about anything that can be executed from a console prompt; for example, a binary executable, shell script, Python script, or batch file.
When executed, the exec()
function creates a system subshell and then executes a command string in that shell just as if you had executed it from a console prompt. This has the advantage of being able to leverage the capabilities of a console shell, such as accessing environment variables on the command line.
The syntax for the exec()
function call is shown below. The execFile()
function call returns a ChildProcess
object:
child_process.exec(command, [options], callback)
The command
parameter is a string that specifies the command to execute in the subshell. The options
parameter is an object that specifies settings to use when executing the command, such as the current working directory. Table 9.7 lists the options that can be specified by the exec()
command.
The callback
parameter is a function that accepts three parameters: error
, stdout
, and stderr
. The error
parameter is passed an error object if an error is encountered when executing the command. stdout
and stderr
are Buffer
objects that contain the output from executing the command.
Table 9.7 Options that can be set when using the exec()
and execFile()
Functions
Property |
Description |
|
Specifies the current working directory for the child process to execute within. |
|
Object whose |
Specifies the encoding to use for the output buffers when storing output from the command. |
|
|
Specifies the size of the output buffers for |
|
Specifies the number of milliseconds for the parent process to wait before killing the child process if it has not completed. The default is |
|
Specifies the kill signal to use when terminating the child process. The default is |
The code in Listing 9.2 illustrates an example of executing a system command using the exec()
function. Listing 9.2 Output shows the result.
Listing 9.2 child_exec.js
: Executing a system command in another process
01 var childProcess = require('child_process'); 02 var options = {maxBuffer:100*1024, encoding:'utf8', timeout:5000}; 03 var child = childProcess.exec('dir /B', options, 04 function (error, stdout, stderr) { 05 if (error) { 06 console.log(error.stack); 07 console.log('Error Code: '+error.code); 08 console.log('Error Signal: '+error.signal); 09 } 10 console.log('Results: ' + stdout); 11 if (stderr.length){ 12 console.log('Errors: ' + stderr); 13 } 14 }); 15 child.on('exit', function (code) { 16 console.log('Completed with code: '+code); 17 });
Listing 9.2 Output child_exec.js
: Executing a system command in another process
Completed with code: 0 Results: chef.js child_fork.js child_process_exec.js child_process_exec_file.js child_process_spawn.js cluster_client.js cluster_server.js cluster_worker.js file.txt process_info.js
execFile()
Another simple method of adding work to another process from a Node.js process is to execute an executable file on another process using the execFile()
function. This is similar to using exec()
except that no subshell is used. This makes execFile()
lighter weight, but it also means that the command to execute must be a binary executable. Shell scripts on Linux and batch files on Windows do not work with the execFile()
function.
The syntax for the execFile()
function call is shown below. The execFile()
function returns a ChildProcess
object:
child_process.execFile(file, args, options, callback)
The file
parameter is a string that specifies the path to the executable file that will be executed. The args
parameter is an array that specifies command-line arguments to be passed to the executable. The options
parameter is an object that specifies settings to use when executing the command, such as the current working directory. Table 9.7 lists the options that can be specified by the execFile()
command.
The callback
parameter is a function that accepts three parameters: error
, stdout
, and stderr
. The error
parameter is passed an error object if an error is encountered when executing the command. stdout
and stderr
are Buffer
objects that contain the output from executing the command.
Listing 9.3 illustrates executing a system command using the execFile()
function. Listing 9.3 Output shows the output.
Listing 9.3 child_process_exec_file.js
: Executing an executable file in another process
01 var childProcess = require('child_process'); 02 var options = {maxBuffer:100*1024, encoding:'utf8', timeout:5000}; 03 var child = childProcess.execFile('ping.exe', ['-n', '1', 'google.com'], 04 options, function (error, stdout, stderr) { 05 if (error) { 06 console.log(error.stack); 07 console.log('Error Code: '+error.code); 08 console.log('Error Signal: '+error.signal); 09 } 10 console.log('Results: ' + stdout); 11 if (stderr.length){ 12 console.log('Errors: ' + stderr); 13 } 14 }); 15 child.on('exit', function (code) { 16 console.log('Child completed with code: '+code); 17 });
Listing 9.3 Output child_process_exec_file.js
: Executing an executable file in another process
Child completed with code: 0 Results: Pinging google.com [216.58.195.78] with 32 bytes of data: Reply from 216.58.195.78: bytes=32 time=47ms TTL=55 Ping statistics for 216.58.195.78: Packets: Sent = 1, Received = 1, Lost = 0 (0% loss), Approximate round trip times in milli-seconds: Minimum = 47ms, Maximum = 47ms, Average = 47ms
spawn()
A more complex method of adding work to another process from a Node.js process is to spawn another process; link the stdio
, stdout
, and stderr
pipes between them; and then execute a file on the new process using the spawn()
function. That makes spawning a bit heavier than exec()
but provides some great benefits.
The major differences between spawn()
and exec()
/execFile()
are that the stdin
for the spawned process can be configured and the stdout
and stderr
are Readable
streams in the parent process. This means that exec()
and execFile()
must complete before reading the buffer outputs. However, you can read output data from a spawn()
process as soon as it is written.
The syntax for the spawn()
function call is shown below. The spawn()
function returns a ChildProcess
object:
child_process.spawn(command, [args], [options])
The command
parameter is a string that specifies the command to be executed. The args
parameter is an array that specifies command-line arguments to be passed to the executable command. The options
parameter is an object that specifies settings to use when executing the command, such as the current working directory. Table 9.8 lists the options that can be specified by the spawn()
command.
The callback
parameter is a function that accepts three parameters: error
, stdout
, and stderr
. The error
parameter is passed an error object if an error is encountered when executing the command. The stdout
and stderr
are defined by the stdio
option settings; by default they are Readable
stream objects.
Table 9.8 Properties of the options
parameter that can be set when using the spawn()
function
Property |
Description |
|
A string representing the current working directory of the child process. |
|
An object whose |
|
A Boolean; when |
|
Specifies the user identity of the process for POSIX processes. |
|
Specifies the group identity of the process for POSIX processes. |
|
An array that defines the child process The following list describes each of the options that can be used:
File Descriptor Integer: Specifies the integer value of a file descriptor to use.
|
Listing 9.4 illustrates executing a system command using the spawn()
function. Listing 9.4 Output shows the output.
Listing 9.4 child_process_spawn_file.js
: Spawning a command in another process
01 var spawn = require('child_process').spawn; 02 var options = { 03 env: {user:'brad'}, 04 detached:false, 05 stdio: ['pipe','pipe','pipe'] 06 }; 07 var child = spawn('netstat', ['-e']); 08 child.stdout.on('data', function(data) { 09 console.log(data.toString()); 10 }); 11 child.stderr.on('data', function(data) { 12 console.log(data.toString()); 13 }); 14 child.on('exit', function(code) { 15 console.log('Child exited with code', code); 16 });
Listing 9.4 Output child_process_spawn_file.js
: Spawning a command in another process
Interface Statistics Received Sent Bytes 893521612 951835252 Unicast packets 780762 5253654 Non-unicast packets 94176 31358 Child exited with code 0 Discards 0 0 Errors 0 0 Unknown protocols 0
Node.js also provides a specialized form of process spawning called a fork, which is designed to execute Node.js module code inside another V8 instance running on a separate processor. This has the advantage of allowing you to run multiple services in parallel. However, it also takes time to spin up a new instance of V8, and each instance takes about 10MB of memory. Therefore, you should design your forked processes to be longer lived, and not require many of them. Remember that you don’t get a performance benefit for creating more processes than you have CPUs in the system.
Unlike spawn
, you cannot configure the stdio
for the child process; instead it is expected that you use the send()
mechanism in the ChildProcess
object to communicate between the parent and child processes.
The syntax for the fork()
function call is shown below. The fork()
function returns a ChildProcess
object:
child_process.fork(modulePath, [args], [options])
The modulePath
parameter is a string that specifies the path to the JavaScript file that is launched by the new Node.js instance. The args
parameter is an array that specifies command-line arguments to be passed to the node
command. The options
parameter is an object that specifies settings to use when executing the command, such as the current working directory. Table 9.9 lists the options that can be specified by the fork()
command.
The callback
parameter is a function that accepts three parameters: error
, stdout
, and stderr
. The error
parameter is passed an error object if an error is encountered when executing the command. The stdout
and stderr
are Readable
stream objects.
Table 9.9 Properties of the options
parameter that can be set when using the fork()
function
Property |
Description |
|
A string representing the current working directory of the child process. |
|
An object whose |
|
Specifies the encoding to use when writing data to the output streams and across the |
|
Specifies the executable to use to create the spawned Node.js process. This allows you to use different versions of Node.js for different processes, although that is not recommended in case the process functionality is different. |
|
A Boolean; when |
Listing 9.5 and Listing 9.6 illustrate examples of forking work off to another Node.js instance running in a separate process. Listing 9.5 uses fork()
to create three child processes running the code from Listing 9.6. The parent process then uses the ChildProcess
objects to send commands to the child processes. Listing 9.6 implements the process.on('message')
callback to receive messages from the parent, and the process.send()
method to send the response back to the parent process, thus implementing the IPC mechanism between the two.
The output is shown in Listing 9.6 Output.
Listing 9.5 child_fork.js
: A parent process creating three child processes and sending commands to each, executing in parallel
01 var child_process = require('child_process'); 02 var options = { 03 env:{user:'Brad'}, 04 encoding:'utf8' 05 }; 06 function makeChild(){ 07 var child = child_process.fork('chef.js', [], options); 08 child.on('message', function(message) { 09 console.log('Served: ' + message); 10 }); 11 return child; 12 } 13 function sendCommand(child, command){ 14 console.log("Requesting: " + command); 15 child.send({cmd:command}); 16 } 17 var child1 = makeChild(); 18 var child2 = makeChild(); 19 var child3 = makeChild(); 20 sendCommand(child1, "makeBreakfast"); 21 sendCommand(child2, "makeLunch"); 22 sendCommand(child3, "makeDinner");
Listing 9.6 chef.js
: A child process handling message events and sending data back to the parent process
01 process.on('message', function(message, parent) { 02 var meal = {}; 03 switch (message.cmd){ 04 case 'makeBreakfast': 05 meal = ["ham", "eggs", "toast"]; 06 break; 07 case 'makeLunch': 08 meal = ["burger", "fries", "shake"]; 09 break; 10 case 'makeDinner': 11 meal = ["soup", "salad", "steak"]; 12 break; 13 } 14 process.send(meal); 15 });
Listing 9.5 Output chef.js
: A child process handling message events and sending data back to the parent process
Requesting: makeBreakfast Requesting: makeLunch Requesting: makeDinner Served: soup,salad,steak Served: ham,eggs,toast Served: burger,fries,shake
One of the coolest things you can do with Node.js is create a cluster of Node.js instances running in parallel in separate processes on the same machine. You can do that using the techniques you learned about the in the previous section by forking processes and then using the send(message, serverHandle)
IPC mechanism to communicate send
messages and pass the underlying TCP server handles between them. However, because that is such a common task, Node.js has provided the cluster
module that does all that for you automatically.
The cluster
module provides the functionality necessary to easily implement a cluster of TCP or HTTP servers running in different processes on the same machine but still using the same underlying socket, thus handling requests on the same IP address and port combination. The cluster
module is simple to implement and provides several events, methods, and properties that can be used to initiate and monitor a cluster of Node.js servers.
Table 9.10 lists the events that can be emitted in a cluster application.
Table 9.10 Events that can be emitted by the cluster
module
Event |
Description |
|
Emitted when a new worker has been forked. The function (worker) |
|
Emitted when the new worker sends back a message indicating that it has started. The function (worker) |
|
Emitted when the worker calls function (worker, address) |
|
Emitted after the IPC channel has been disconnected, such as the server calling function (worker) |
|
Emitted when the function (worker, code, signal) |
|
Emitted the first time the |
Table 9.11 lists the methods and properties available in the cluster
module, allowing you to get information such as whether this node is a worker or the master as well as configuring and implementing the forked processes.
Table 9.11 Methods and properties of the cluster
module
Property |
Description |
|
Contains the |
|
Is |
|
Is |
|
Accepts an optional settings object that contains |
|
Disconnects the IPC mechanism from the workers and closes the handles. The |
|
References the current |
|
Contains the cluster.workers[workerId] |
Worker
ObjectWhen a worker process is forked, a new Worker
object is created in both the master and worker processes. In the worker process, the object is used to represent the current worker and interact with cluster events that are occurring. In the master process, the Worker
object is used to represent child worker processes so that your master application can send messages to them, receive events on their state changes, and even kill them.
Table 9.12 lists the events that Worker
objects can emit.
Table 9.12 Events that can be emitted by Worker
objects
Event |
Description |
|
Emitted when the worker receives a new message. The |
|
Emitted after the IPC channel has been disconnected on this worker. |
|
Emitted when this |
|
Emitted when an error has occurred on this worker. |
Table 9.13 lists the methods and properties available in the Worker
object, allowing you to get information such as whether this node is a worker or the master as well as configuring and implementing the forked processes.
Table 9.13 Methods and properties of the Worker
module
Property |
Description |
|
Represents the unique ID of this worker. |
|
Specifies the |
|
Is set to |
|
Sends a message to the master process. |
|
Kills the current worker process by disconnecting the IPC channel and then exiting. Sets the |
|
When called in the worker, closes all servers, waits for the |
The best way to illustrate the value of the cluster
module is to show a basic implementation of Node.js HTTP servers. Listing 9.7 implements a basic cluster of HTTP servers. Lines 4–13 register listeners for the fork
, listening
, and exit
events on cluster workers. Then in line 14 setupMaster()
is called and the worker executable cluster_worker.js
is specified. Next, lines 15–19 create the workers by calling cluster.fork()
. Finally, in lines 20–24 the code iterates through the workers and registers an on('message')
event handler for each one.
Listing 9.8 implements the worker HTTP servers. Notice that the http
server sends back a response to the client and then also sends a message to the cluster master on line 7.
Listing 9.9 implements a simple HTTP client that sends a series of requests to test the servers created in Listing 9.8. The output of the servers is shown in Listing 9.7 and 9.8 Output, and the output of the clients is shown in Listing 9.9 Output. Notice that Listing 9.9 Output shows that the requests are being handled by different processes on the server.
Listing 9.7 cluster_server.js
: A master process creating up to four worker processes
01 var cluster = require('cluster'); 02 var http = require('http'); 03 if (cluster.isMaster) { 04 cluster.on('fork', function(worker) { 05 console.log("Worker " + worker.id + " created"); 06 }); 07 cluster.on('listening', function(worker, address) { 08 console.log("Worker " + worker.id +" is listening on " + 09 address.address + ":" + address.port); 10 }); 11 cluster.on('exit', function(worker, code, signal) { 12 console.log("Worker " + worker.id + " Exited"); 13 }); 14 cluster.setupMaster({exec:'cluster_worker.js'}); 15 var numCPUs = require('os').cpus().length; 16 for (var i = 0; i < numCPUs; i++) { 17 if (i>=4) break; 18 cluster.fork(); 19 } 20 Object.keys(cluster.workers).forEach(function(id) { 21 cluster.workers[id].on('message', function(message){ 22 console.log(message); 23 }); 24 }); 25 }
Listing 9.8 cluster_worker.js
: A worker process implementing an HTTP server
01 var cluster = require('cluster'); 02 var http = require('http'); 03 if (cluster.isWorker) { 04 http.Server(function(req, res) { 05 res.writeHead(200); 06 res.end("Process " + process.pid + " says hello"); 07 process.send("Process " + process.pid + " handled request"); 08 }).listen(8080, function(){ 09 console.log("Child Server Running on Process: " + process.pid); 10 }); 11 };
Listing 9.9 cluster_client.js
: An HTTP client sending a series of requests to test the server
01 var http = require('http'); 02 var options = { port: '8080' }; 03 function sendRequest(){ 04 http.request(options, function(response){ 05 var serverData = ''; 06 response.on('data', function (chunk) { 07 serverData += chunk; 08 }); 09 response.on('end', function () { 10 console.log(serverData); 11 }); 12 }).end(); 13 } 14 for (var i=0; i<5; i++){ 15 console.log("Sending Request"); 16 sendRequest(); 17 }
Listing 9.7 and 9.8 Output cluster_server.js
: A master process creating up to four worker processes
Worker 1 created Worker 2 created Worker 3 created Worker 4 created Child Server Running on Process: 9012 Worker 1 is listening on null:8080 Child Server Running on Process: 1264 Worker 2 is listening on null:8080 Child Server Running on Process: 5488 Worker 4 is listening on null:8080 Child Server Running on Process: 7384 Worker 3 is listening on null:8080 Process 1264 handled request Process 7384 handled request Process 5488 handled request Process 7384 handled request Process 5488 handled request
Listing 9.9 Output cluster_client.js
: An HTTP client sending a series of requests to test the server
Sending Request Sending Request Sending Request Sending Request Sending Request Process 10108 says hello Process 12584 says hello Process 13180 says hello Process 10108 says hello Process 12584 says hello
To make the most out of Node.js performance on servers with multiple processors, you need to be able to farm work off to the other processes. The process
module allows you to interact with the system process, the child_process
module allows you to actually execute code on a separate process, and the cluster
module allows you to create a cluster of HTTP or TCP servers.
The child_process
module provides the exec()
, execFile()
, spawn()
, and fork()
functions, which are used to start work on separate processes. The ChildProcess
and Worker
objects provide a mechanism to communicate between the parent and child processes.
3.147.44.118