Home

Processes

Node includes the process object, which contains a bunch of properties and details about the current running process.

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.jswill 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 and system - each holds a set of microseconds representing the CPU time used by each. The user is the node process. the system is the kernel
  • memoryUsage() will return an object with 5 keys, each with values in bytes:
    • rss: residential set size - ram for the process
    • heapTotal: - 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 objects
    • arrayBuffers: memory allocated for ArrayBuffers and SharedArrayBuffers through node. The arrayBuffers value is also part of the external 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')
}
Tags: