Create and manage external processes in Node.js _node.js

Source: Internet
Author: User
Tags setinterval sleep stdin

node is designed to efficiently handle I/O operations, but you should know that some types of programs are not appropriate for this pattern. For example, if you're going to use node to handle a CPU-intensive task, you may be blocking the event loop, and thus lowering the program's response. Instead, the CPU-intensive task is assigned to a separate process to handle, freeing up the event loop. node allows you to generate a process and make the new process a child of its parent process. In node, the subprocess can communicate with the parent process in both directions, and to some extent, the parent process can also monitor and manage the child processes.

Another situation where you need to use a subprocess is when you want to simply execute an external command and have node get the return value of the command. For example, you can execute a UNIX command, script, or other command that can't be executed directly in node.

This chapter will show you how to execute external commands, create, and communicate with child processes, and terminate child processes. The point is to let you know how to accomplish a series of tasks outside of the node process.

Execute external command

When you need to execute an external shell command or executable file, you can use the Child_process module to import it like this:

Copy Code code as follows:

var child_process = require (' child_process ')

You can then use the EXEC function within the module to execute the external command:
Copy Code code as follows:

var exec = child_process.exec;

EXEC (Command,callback);


The first parameter of exec is the shell command string you are going to execute, and the second parameter is a callback function. This callback function will be invoked when exec executes an external command or when an error occurs. The callback function has three parameters: Error,stdout,stderr, look at the following example:
Copy Code code as follows:

EXEC (' ls ', function (Err,stdout,stderr) {

If you use Windows, you can change to Windows command, such as Dir, and don't repeat the following

});

If an error occurs, the first argument will be an instance of an error class, and if the first argument contains no errors, the second argument stdout will contain the standard output of the command. The last parameter contains a command-related error output.

Listing 8-1 shows a more complex example of executing an external command

LISTING 8-1: Execute external command (Source: chapter8/01_external_command.js)

Copy Code code as follows:

exec function to import child_process module
var exec = require (' child_process '). exec;
Call "Cat *.js | Wc-l "command
EXEC (' Cat *.js | wc–l ', function (err, stdout, stderr) {//Line Fourth
Command exit or call failed
if (err) {
Failed to start external process
Console.log (' child_process exit, error code is: ', err.code);
Return
}
}

Line four, we put "cat *.js | Wc-l "As the first parameter passed to exec, you can also try any other command, as long as the commands you have used in the shell are OK.

A callback function is then used as the second argument, which is invoked when the error occurs or the child process ends.

You can also pass a third optional parameter before the callback function, which contains some configuration options, such as:

Copy Code code as follows:

var exec = require (' child_process '). exec;

var options ={
timeout:1000,
Killsignal: ' SIGKILL '
};

EXEC (' Cat *.js | wc–l ', options, function (Err,stdout,stderr) {
...
});

The parameters that can be used are:

1.cwd--The current directory, you can specify the current working directory.
2.encoding--the encoding of the output of the subprocess, the default value is "UTF8", which is the UTF-8 encoding. If the output of the subprocess is not UTF8, you can use this parameter to set the supported encoding formats:

Copy Code code as follows:

Ascii
Utf8
Ucs2
Base64

If you want to learn more about these coded formats that node supports, refer to chapter 4th, "Using buffer processing, encoding, decoding binary data."

1.timeout--the command execution timeout in milliseconds, the default is 0, unrestricted, until the child process ends.
2.maxbuffer--Specifies the maximum number of bytes that the stdout stream and the stderr stream allow to output, and if the maximum is reached, the child process is killed. The default value is 200*1024.
3.killsignal--the end signal sent to a subprocess when the timeout or output cache reaches its maximum value. The default value is "Sigterm", which sends an end signal to the child process. This is often used in an orderly way to end a process. When the sigterm signal is used, the process can receive later to process or rewrite the default behavior of the signal processor. If the target process requires it, you can send other signals (such as SIGUSR1) to him at the same time. You can also choose to send a sigkill signal, which will be processed by the operating system and forced to terminate the subprocess immediately, so that any cleanup of the child process will not be performed.

If you want to further control the end of the process, you can use the Child_process.spawn command, which is described later.

1.evn--Specifies the environment variable passed to the child process, which defaults to null, meaning that the child process inherits the environment variables of all the parent processes before it was created.

Note: Using the killsignal option, you can send a signal to the target process as a string. In node the signal is in the form of a string, and the following is a list of UNIX signals and corresponding default actions:

You may want to provide a child process with a set of extensible parent environment variables. If you modify the Process.env object directly, you will change the environment variables of all the modules in the node process, which can cause a lot of trouble. The alternative is to create a new object and copy all the parameters in the Process.env, as shown in example 8-2:

LISTING 8-2: Use parameterized environment variables to execute commands (source: chapter8/02_env_vars_augment.js)

Copy Code code as follows:

var env = process.env,
VarName,
Envcopy = {},
exec = require (' child_prcess '). exec;
Copy Process.env to Envcopy
For (vaname in EV) {
Envcopy[varname] = Env[varname];
}

Set some custom variables
envcopy[' CUSTOM ENV VAR1 '] = ' some value ';
envcopy[' CUSTOM ENV VAR2 '] = ' some other value ';

Use process.env and custom variables to execute commands
EXEC (' Ls–la ', {env:envcopy}, function (Err,stdout,stderr) {
if (err) {throw err;}
Console.log (' stdout: ', stdout);
Console.log (' stderr: ', stderr);
}

In the example above, a envcopy variable is created to hold the environment variable, It first replicates the environment variables of the node process from process.env, then adds or replaces some environment variables that need to be modified, and finally passes the envcopy as an environment variable parameter to the EXEC function and executes an external command.

Remember, environment variables are passed between processes through the operating system, and all types of environment variable values reach the child process as strings. For example, if the parent process takes the number 123 as an environment variable, the child process will receive "123" as a string.

In the following example, 2 node scripts will be created in the same directory: Parent.js and Child.js, the first script will call the second, and below we'll create the two files:

LISTING 8-3: The parent process sets the environment variable (chapter8/03_environment_number_parent.js)

Copy Code code as follows:

var exec = require (' child_process '). exec;

EXEC (' node Child.js ', {env: {number:123}}, function (Err, stdout, stderr) {

if (err) {throw err;}

Console.log (' stdout:\n ', stdout);

Console.log (' stderr:\n ', stderr);

});

Save this code to Parent.js, below is the source of the subprocess, save them to child.js (see example 8-4)

Example 8-4: Child process resolution environment variable (CHAPTER8/04_ENVIRONMENT_NUMBER_CHILD.JS)

Copy Code code as follows:

var number = Process.env.number;

Console.log (typeof (number)); → "string"

Number = parseint (number, 10);

Console.log (typeof (number)); → "number"

When you save this file as a child.js, you can run the following command in this directory:

Copy Code code as follows:

$ node Parent.js

You will see the following output:

Copy Code code as follows:

Sdtou:

String

Number

StdErr

As you can see, although the parent process passed a numeric environment variable, the child process receives it as a string (see the second line of output), and in the third line you parse the string into a number.

Build child process

As you can see, it's easy to use the Child_process.exec () function to start an external process and call your callback function at the end of the process, but there are some drawbacks:

1. In addition to using command line arguments and environment variables, using EXEC () cannot communicate with child processes
2. The output of the subprocess is cached, so you cannot stream it, and it may run out of memory

Fortunately, node's child_process module allows finer-grained control of child processes to start, stop, and other general operations. You can start a new subprocess in your application, and node provides a two-way communication channel that allows the parent and child processes to send and receive string data from one another. The parent process can also have some administrative actions on the child process, send a signal to the child process, and force the child process to close.

To create a child process

You can use the Child_process.spawn function to create a new subprocess, see example 8-5:

Example 8-5: Generate child processes. (chapter8/05_spawning_child.js)

Copy Code code as follows:

Import the Spawn function of the child_process module

var spawn = require (' child_process '). Spawn;

Generate a subprocess to perform the tail-f/var/log/system.log command

var child = spawn (' tail ', [' f ', '/var/log/system.log ']);

The code above generates a subprocess to execute the tail command and takes "-F" and "/bar/log/system.log" as arguments. The tail command will monitor the/var/log/system.og file (if it exists) and then output all additional new data to the STDOUT standard output stream. The Spawn function returns a Childprocess object, which is a pointer object that encapsulates the access interface of the real process. In this example, we give the new description assignments to a variable called the child.

Listening for data from child processes

Any child process handle that contains the StdOut property will have the standard output stdout of the subprocess as a stream object, and you can bind the data event to the stream object so that whenever a block is available, the corresponding callback function is invoked, as shown in the following example:

Copy Code code as follows:

Print the output of a child process to the console

Child.stdout.on (' Data ', function (data) {

Console.log (' Tail output: ' + data);

});

Whenever a subprocess outputs data to the standard output stdout, the parent process is notified and the data is printed to the console.

In addition to the standard output, there is another default output stream for the process: the standard error stream, which typically uses this stream to output the error message.

In this example, if the/var/log/system.log file does not exist, the tail process will output a message similar to the following: "/var/log/system.log:no such file or directory", by listening for the stderr stream, The parent process is notified when this error occurs.

The parent process can listen to the standard error stream in this way:

Copy Code code as follows:

Child.stderr.on (' Data ', function (data) {

Console.log (' Tail error output: ', data);

});

The StdErr property, like the stdout, is read-only, and whenever the child processes output data to the standard error stream, the parent process is notified and the data is output.

Sending data to a child process

In addition to receiving data from the output stream of a child process, the parent process can send data to and from the child process by writing data to the standard input of the subprocess through the Childpoces.stdin property.

A subprocess can listen to standard input data by Process.stdin a read-only stream, but note that you first have to recover (resume) the standard input stream because it is in a paused (paused) state by default.

Example 8-6 will create a program that includes the following features:

1.+1 Application: A simple application that receives an integer from the standard input and then adds it, then outputs the added results to the standard output stream. As a simple computing service, this application simulates the node process as an external service that can perform specific tasks.

2. Test +1 application client, send random integer, then output the result. Used to demonstrate how the node process generates a child process and then lets it perform a specific task.

Create a file named Plus_one.js with the code in the following example 8-6:

Example 8-6: +1 application (chapter8/06_plus_one.js)

Copy Code code as follows:

Restore the standard input stream by default is paused state
Process.stdin.resume ();
Process.stdin.on (' Data ', function (data) {
var number;
try {
Resolve input data to integral type
Number = parseint (data.tostring (), 10);
+1
Number = 1;
Output results
Process.stdout.write (number + "\ n");
} catch (Err) {
Process.stderr.write (err.message + "\ n");
}
});

In the code above, we wait for data from the STDIN standard input stream, and whenever the data is available, assume it's an integer and parse it into an integer variable, then add 1 and output the result to the standard output stream.

You can run this program by using the following command:

Copy Code code as follows:

$ node Plus_one.js

The running program starts waiting for input, and if you enter an integer and then press ENTER, you will see a number added to the 1 that is displayed on the screen.

You can exit the program by pressing CTRL-C.

A test client

Now you want to create a node process to use the computing services provided by the previous "+1 applications".

First, create a file named Plus_one_test.js, as shown in example 8-7:

Example 8-7: Test +1 application (chapter8/07_plus_one_test.js)

Copy Code code as follows:

var spawn = require (' child_process '). Spawn;
Generate a subprocess to perform the +1 application
var child = spawn (' node ', [' plus_one.js ']);
Call a function every second
SetInterval (function () {
Create a random number smaller than 10.000
var number = Math.floor (Math.random () * 10000);
Send this number to the child process:
Child.stdin.write (number + "\ n");
Get the response from the child process and print it:
Child.stdout.once (' Data ', function (data) {
Console.log (' child replied to ' + number + ' with: ' + data);
});
}, 1000);
Child.stderr.on (' Data ', function (data) {
Process.stdout.write (data);
});

From the first line to line fourth, you start a subprocess that runs the +1 application, and then use the SetInterval function to perform the following actions every second:

1. Create a new random number less than 10000
2. Pass this number as a string to the child process
3. Wait for child process to reply to a string
4. Because you want to receive a calculation of only 1 digits at a time, you need to use child.stdout.once instead of Child.stdout.on. If the latter is used, the callback function of a data event is registered every 1 seconds, and each registered callback function is executed when the stdout of the child process receives the data, so that you will find that the same calculation will be output multiple times, and this behavior is clearly wrong.

Receive notification when a child process exits

The exit event is triggered when the child process exits. Example 8-8 shows how to listen for it:

Example 8-8: The exit event that listens for a subprocess (chapter8/09_listen_child_exit.js)

Copy Code code as follows:

var spawn = require (' child_process '). Spawn;
To build a subprocess to execute the "Ls-la" command
var child = spawn (' ls ', ['-la ']);
Child.stdout.on (' Data ', function (data) {
Console.log (' Data from Child: ' + data ');
});

When the child process exits:
<strong>child.on (' Exit ', function (code) {
Console.log (' child process terminated with code ' + code);
});</strong>

In the last few lines, the black code, the parent process uses the child process's exit event to listen for its exit events, and when the event occurs, the console displays the corresponding output. The exit code for the child process is passed as the first argument to the callback function. Some programs use a non-0 exit code to represent some kind of failed state. For example, if you try to execute the command "Ls–al click filename.txt", but the current directory does not have this file, you will get a value of 1 exit code, see example 8-9:

Example 8-9: Get the exit code for the subprocess (chapter8/10_child_exit_code.js)

Copy Code code as follows:

var spawn = require (' child_process '). Spawn;
Build subprocess, execute "LS does_not_exist.txt" command
var child = spawn (' ls ', [' does_not_exist.txt ']);
When a child process exits
Child.on (' Exit ', function (code) {
Console.log (' child process terminated with code ' + code);
});

In this example, the Exit event triggers the callback function and passes the exit code of the process to it as the first argument. If the subprocess is an abnormal exit caused by a signal killing, then the corresponding signal code is passed as the second parameter to the callback function, as in example 8-10:

LISTING 8-10: Get the exit signal for the subprocess (chapter8/11_child_exit_signal.js)

Copy Code code as follows:

var spawn = require (' child_process '). Spawn;
To build the child process, run the Sleep 10 command
var child = spawn (' Sleep ', [' 10 ']);
settimeout (function () {
Child.kill ();
}, 1000);
Child.on (' Exit ', function (code, signal) {
if (code) {
Console.log (' child process terminated with code ' + code);
else if (signal) {
Console.log (' child process terminated because of signal ' + signal);
}
});

In this example, a subprocess is initiated to perform a sleep 10-second operation, but a sigkill signal is sent to the child process in less than 10 seconds, which results in the following output:

Copy Code code as follows:

Child process terminated because of signal sigterm

Send a signal and kill the process

In this section, you will learn how to use signals to manage child processes. A signal is a simple way for a parent to communicate with a child process, or even to kill a child process.

Different signal codes represent different meanings, there are many signals, and some of the most common are used to kill processes. If a process receives a signal that it does not know how to handle, the program is interrupted abnormally. Some of the signals are processed by the quilt, and some can only be handled by the operating system.

In general, you can use the Child.kill method to send a signal to the subprocess, sending the sigterm signal by default:

Copy Code code as follows:

var spawn = require (' child_process '). Spawn;
var child = spawn (' Sleep ', [' 10 ']);
settimeout (function () {
Child.kill ();
}, 1000);

You can also send a specific signal by passing in a string that identifies the signal as a unique parameter to the Kill method:

Copy Code code as follows:

Child.kill (' SIGUSR2 ');

It should be noted that although the name of this method is called kill, the signal sent does not necessarily kill the subprocess. If the subprocess processes the signal, the default signal behavior is overwritten. A child process written with node can override the definition of a signal processor as follows:

Copy Code code as follows:

Process.on (' SIGUSR2 ', function () {
Console.log (' Got a SIGUSR2 signal ');
});

Now, you define the SIGUSR2 signal processor, and when your process receives the SIGUSR2 signal, it will not be killed, but rather the word "Got a SIGUSR2 signal" is exported. Using this mechanism, you can design a simple way to communicate with the subprocess or even command it. While not as rich as the standard input feature, this is a much simpler approach.

Summary

In this chapter, you learn to use the Child_process.exec method to execute external commands, which can be passed to the child process by defining the environment variables instead of using command-line arguments.

You also learned to invoke an external command by calling the Child_process.spawn method to generate a subprocess, in which you can use an input stream, an output stream to communicate with a subprocess, or use a signal to communicate with a child process and kill a process.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.