Processes
Node includes the process object, which contains a bunch of properties and details about the current running process.
- Processes
- Interact with the terminal using stdio
- Interact With the terminal using stdout
- Determine If A Process Started From The Terminal
- Use Bash To Send Output Somewhere Using '>'
- Use Bash To Separate stdout and stderr outputs
- Parse Command-Line Arguments
- Force A Process to Exit (or quit)
- Get Information about the Running Process
- See And Set Environment Variables
Interact with the terminal using stdio
the process object contains a few streams: stdin, stdout, and stderr.
stdin for process input
process.stdin can be used to interact with process input.
A Trivial script to print to stdout
In most node development use-cases, process.stdin
means handling process input.
Take for example, as a start, this command that can be run in bash on a machine that has node installed: node -e "console.log('this is a string')";
. This uses node to evaluate, with the -e
flag, the subsequent text of the console.log
message. Running this will print this is a string
to the terminal.
Using stdin in a node script
The above bash script can be passed to a |
pipe onto yet another script. Here's a script that will consume the stdin from above:
// myStdin.js
console.log('inside stdin.js');
process.stdin.on('data', d => {
console.log(d.toString())
})
Putting It All Together
node -e "console.log('this is a string');" | node myStdin.js
inside myStdin.js
this is a string
Interact With the terminal using stdout
The myStdin.js
file can be adusted to leverage the process.stdout
stream, which is somewhat like console.log
:
// myStdin.js
console.log('inside stdin.js');
process.stdin.pipe(process.stdout)
This uses the pipe method of the stdin readable stream and passes along the writable stream that is process.stdout
.
Determine If A Process Started From The Terminal
Node includes a detail that allows us as developers to "check" how a node process was started.
A node process can be started directly from the command line (terminal) with something like node <file-name>.js
.
A node process can be piped to from the terminal with something like node -e "console.log('this is a string');" | node <file-name>.js
.
There are also other ways that a node process can be started.
To determine, in code, whether or not the code was ran from the command-line (terminal), a variable can be used: process.stdin.isTTY
.
Let's add a line to the myStdin.js
file above:
// myStdin.js file
console.log('inside stdin.js from',process.stdin.isTTY ?'terminal' : 'pipe');
process.stdin.pipe(process.stdout);
Now, running the file with node myStdin.js
will output
inside stdin.js from terminal
and keep the process "open". Running the file via node -e "console.log('this is a string');" | node stdin.js
will output
inside stdin.js from pipe
this is a string
Use Bash To Send Output Somewhere Using '>'
Let's Run the same process as above and include a bit to send the output to a file called filled-via-bash.txt
:
node -e "console.log('this is a string');" | node stdin.js > filled-via-bash.txt
The new piece is > filled-via-bash.txt
, which "takes" the "data" from the previous command(s), which will be the text seen above, and "sends" the data to where we write next. In our case, this is a file called filled-via-bash.txt
.
Perhaps an interesting detail here is that the file, filled-via-bash.txt
, doesn't even exist. The file might not NEED to exist, necessarily.
Use Bash To Separate stdout and stderr outputs
Let's update our trivial toy process to include a stdout via process.stdout
and a stderr via console.error
:
// myStdin.js
console.error('inside stdin.js from',process.stdin.isTTY ?'terminal' : 'pipe');
process.stdin.pipe(process.stderr);
Now, we can update the line we use to run the process to instruct bash to send error output to a separate location than the stdout:
node -e "console.log('this is a string');" | node stdin.js > filled-via-bash.txt 2> filled-via-bash-err.txt
. After running that version of the process, which now includes the 2> filled-via-bash-err.txt
detail, there will be two files: one with the console.log
output and one with the stderr
output.
Parse Command-Line Arguments
Running the myStdin.js
file, and any js-for-node file for that matter, can also leverage command-line arguments.
Node includes a detail for devs to read command-line arguments.
Let's update the myStdin.js
file and how it gets run to leverage a command-line argument.
Force A Process to Exit (or quit)
Node includes a detail to exit a process.
Let's add this to the myStdin.js
file so that when the process is run from the command-line, directly, the process does not "hang" and quits after logging:
// myStdin.js
console.error('inside stdin.js from', process.stdin.isTTY ? 'terminal' : 'pipe');
process.stdin.pipe(process.stderr);
if (process.stdin.isTTY) {
process.exit();
}
This will exit the process when the the process is run from the terminal (node myStdin.js) and not via a pipe.
Use exit(1) To Exit With An Error
The process.exit
can take a code number as a parameter, with something like process.exit(1)
.
Let's update the myStdin.js
process to exit with code 1
when it is run directly from the cli and not piped to:
// myStdin.js
if (process.stdin.isTTY) {
console.error('Error: stdin not intended to run from tty');
process.exit(1);
}
console.log('stdin ran')
process.stdin.pipe(process.stderr);
Now, running node myStdin.js
will print the error text to the terminal output, but node -e "console.log('this is a string');" | node stdin.js > filled-via-bash.txt 2> filled-via-bash-err.txt
will send content to the two output files (mentioned above)
Use exitCode To Exit With An Error
// myStdin.js
if (process.stdin.isTTY) {
console.error('Error: stdin not intended to run from tty');
process.exitCode = 1;
process.exit();
}
console.log('stdin ran')
process.stdin.pipe(process.stderr);
Code When The Process Exits
When exit()
is called, the exit event is emitted and can be listened for: (for more on events see here)
// myStdin.js
function exitListener(exitCode) {
console.log(`stdin process exited with code ${exitCode}`)
}
if (process.stdin.isTTY) {
console.error('Error: stdin not intended to run from tty');
process.exitCode = 1;
process.exit();
}
console.log('stdin ran');
process.on('exit', exitListener);
process.stdin.pipe(process.stderr);
Get Information about the Running Process
The process module included in node provides a bunch of methods and properties that we as devs can use to get info about the running process. here's a few:
// showInfo.js
console.log({
'cwd': process.cwd(),
'Process Platform': process.platform,
pid: process.pid,
uptime: process.uptime(), //this is in seceonds with a bunch of decimal places
cpuUsage: process.cpuUsage(),
memoryUsage: process.memoryUsage()
})
cpuUsage()
returns an object with two keys:user
andsystem
- each holds a set of microseconds representing the CPU time used by each. Theuser
is the node process. thesystem
is the kernelmemoryUsage()
will return an object with 5 keys, each with values in bytes:rss
: residential set size - ram for the processheapTotal
: - total memory allocated for the process. THIS can be split ACROSS ram AND swap space (a V8 detail)heapUsed
: total memory across BOTH ram and swap space (a v8 detail)external
: memory used by the C++ "layer" of objects that are JS objectsarrayBuffers
: memory allocated forArrayBuffers
andSharedArrayBuffers
through node. ThearrayBuffers
value is also part of theexternal
value.
See And Set Environment Variables
The env property can also be used to see all of the environment variables set on the current process:
console.log(process.env)
In regular node rest api development, env vars are often used to inform the code on any logic that might only be needed in either a development
or production
or testing
(etc) environment.
There are a bunch of ways to set env vars, here's one:
When running a node process the env var could be set when calling or running the node process: MY_VAR_NAME=i_set_this_myself node showit.js
Then in the code the env var could be used:
// showit.js
if(process.env?.MY_VAR_NAME){
console.log(`I set MY_VAR_NAME to ${process.env.MY_VAR_NAME}`)
}else{
console.log('I did not set MY_VAR_NAME')
}