Stderr of child process not received when child process exits - node.js

We have a VS Code extension built in node that runs like so:
Our extension is a node process, it calls child_process.spawn(...), with pipe option for the stdio. The child process' stdin and stdout are used to pass messages between the two processes.
Due to a bug in the child process binary, we see an issue where SIGSEGV error code is thrown by the binary. When we call into the process on the commandline and hit this error, we see the stack trace is dumped to stderr.
In the VS Code extension/node process, we see the handlers for the child process exiting are hit, however the handlers for the stderr output do not.
In other non-crashing scenarios, we see stderr output is correctly transmitted.
The implementation of spawning and handling the child process is reasonably complex, however it boils down to something like this:
child_process.ChildProcess childProcess;
startChildProcess() {
this.childProcess = child_process.spawn(binary, args, {
cwd: root,
env: {...process.env, ...environment},
// pipe stdin and stdout, and inherit stderr (unless parent know better)
stdio: ['pipe', 'pipe', 'pipe'],
});
// set up stdin and stdout pipes here...
this.childProcess.on('exit', (code, signal) => {
// do something interesting when the process exits
// THIS CODE BLOCK IS HIT
}
this.childProcess.stderr?.addListener('data', (errOutput) => {
const errOutputStr = errOutput.toString();
process.stderr.write(errOutputStr);
// THIS CODE BLOCK IS NOT HIT WHEN THE ABOVE IS HIT
})
}
As annotated in the example, the stderr output is not hit in the case of a SIGSEGV from child process.
What can I do to ensure the errors are output? VS Code, the extension process and the child process are all running on Mac OS

Related

Error handling using child_process.execSync in NodeJs

This is my NodeJs snippet:
const {execSync} = require('child_process');
testoutput = execSync('make test');
Here I am getting stdout as output to testoutput variable from the execSync process if the make process is completely exited. But, if the make test process encounters an stderr error then I am getting an error in NodeJs.
How can I store the stderr message to an output variable testoutput if the make process does not exit and store stdout in variable testoutput if the process exits well with stdout output.
To catch errors with execSync(), you need a try/catch around your call as errors will throw an exception.

NodeJS child_process: close event not fired when specifying stdio: "inherit"

I am trying to execute some commands in the shell using NodeJS. Therefore I use the node:child_process module.
I use the spawn function in order to be able to forward the output of the child process to the console of the main process.
In order to keep the formatting of the output of the child process I passed the option stdio: "inherit" (as described in this question: preserve color when executing child_process.spawn).
But if I add this option the child process events (exit, disconnect, close, ...) don't work anymore. If I get rid of the option I lose the formatting, but the events work. Is there a way to keep the formatting and be informed, when the child process closes?
The (relevant) code:
const { spawn } = require("node:child_process");
let child = spawn("yarn", args, {
stdio: "inherit",
shell: true,
});
child.on("close", (code) => {
console.log(`child process exited with code ${code}`);
});
stdio: 'inherit' means you're also forwarding your STDIN to the child process, therefore if the child process reads STDIN, it will never exit, and your close listener will never be called. In particular, that's the case for Node.JS REPL (yarn node).
Depending on your needs, you may want to:
just stop the child process with child.kill(). The close listener is then called, note that code is 0, and the second argument (signal) is SIGTERM (documentation);
do not forward STDIN but still forward STDOUT and STDERR back: call spawn with stdio: ['ignore', 'inherit', 'inherit'] (documentation). When the child process will exit by itself and the streams released, the close listener will be called.

What are the ways to flush a Linux command's stdout as a Node.js child process?

What are the ways to flush a Linux command's stdout as a Node.js child process?
Ending the stdin stream (child.stdin.end) will work. As will unbuffering the command with stdbuf.
But I imagine there's a proper way to stream results from external commands.
How do we tell a command we're ready to consume while we are still providing data?
Example:
const { spawn } = require('child_process');
const child = spawn('uniq');
child.stdout.pipe(process.stdout);
child.stdin.write('a\nb\nb\nc\n', 'utf8');
// No output, child is still running.
(uniq is just an example here. It's the same with most Linux commands.)

Create child process that duplicates stderr of main process

Is there a stable way I can create a child process that hangs out in the background and inherits stderr, in and out? From what I see, creating a child requires me to launch a separate program. Instead I want to create a child process that lasts as long as the main process, and only serves to allow me to duplicate stderr so I can read from it.
Here's an example of creating a process inside the link
use std::process::Command;
let output = Command::new("sh")
.arg("-c")
.arg("echo hello")
.output()
.unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });
let hello = output.stdout;
what I'd like to do
use std::process::Command;
let leech = Command::new() // create process that hangs out in the background and inherits stderr, stdin and stdout from main process
// ....
// panic occurs somewhere in the program
if thread::panicking {
output = leech.output().stderr();
}
// screen clears
// print stderr of output
I need to create a leech of sorts because panics being displayed to the main screen are flushed due to terminal graphics. The library will clear the screen which in the process clears away panic messages, If I was able to duplicate stderr and somehow read it, I could reprint the panic message after the terminal restored the pre-program-running state.
I believe this is easier to do with a wrapper program, instead of launching something from the rust program itself. Here's an example of how to do it using shell script:
#!/bin/bash
# Redirection magic from http://stackoverflow.com/a/6317938/667984
{ errors=$(./my_rust_program 2>&1 1>&$original_out); } {original_out}>&1
if [[ $? -ne 0 ]]; then
echo
echo "--terminal reset shenanigans--"
echo
echo "$errors" >&2
fi
When used with this rust program:
fn main() {
println!("Normal program output");
panic!("oops");
}
It prints:
Normal program output
--terminal reset shenanigans--
thread '<main>' panicked at 'oops', my_rust_program.rs:3
I believe you can create one in stable rust as well, but since you mention sh in your question I assume you are in a unix environment anyway, and the shell script version should be simpler.

Node-webkit execute external command?

How to execute system command in node-webkit (or node.js) external process parallel of current script.
I'm trying to use child_process. After interruption of my script subprocess is exit. However i need a simple way execute bash command without output or with output but without program stop when my script will be interrupted.
I need a correct simple way.
Thanks all.
Use detached option in spawn/execute arguments:
If the detached option is set, the child process will be made the
leader of a new process group. This makes it possible for the child to
continue running after the parent exits.
By default, the parent will wait for the detached child to exit. To
prevent the parent from waiting for a given child, use the
child.unref() method, and the parent's event loop will not include the
child in its reference count.
Example of detaching a long-running process and redirecting its output
to a file:
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
var child = spawn('prg', [], {
detached: true,
stdio: [ 'ignore', out, err ]
});
child.unref();

Resources