Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process does not die when child process to which stdin is piped dies #24327

Closed
masaeedu opened this issue Nov 12, 2018 · 6 comments
Closed

Process does not die when child process to which stdin is piped dies #24327

masaeedu opened this issue Nov 12, 2018 · 6 comments
Labels
child_process Issues and PRs related to the child_process subsystem. invalid Issues and PRs that are invalid.

Comments

@masaeedu
Copy link

  • Version: v10.3.0
  • Platform: Linux plutobox 4.18.16-arch1-1-ARCH deps: update openssl to 1.0.1j #1 SMP PREEMPT Sat Oct 20 22:06:45 UTC 2018 x86_64 GNU/Linux
  • Subsystem: child_process/stream/process

Basically a duplicate of: #2276, which was either closed without having been resolved or has regressed.

Stick the following in a file:

#!/usr/bin/env node
const cp = require("child_process");

const { stdin, stdout, stderr } = process;
const child = cp.execFile("ps", [], { stdio: ["pipe", "pipe", "pipe"] });

process.stdin.pipe(child.stdin); // this is the problematic one
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

child.on("exit", (code, signal) =>
  console.log({ msg: "Exited", code, signal }),
);

chmod +x and run it in some shell, and you'll see it'll output the stuff from ps, then just hang. Assuming your shell's stdin is being forwarded to the node process, hitting enter will unstick it. If you comment out the process.stdin... line (since ps doesn't actually need any stdin), you'll see it end as expected.

The workaround I'm using for this is to add the event handler child.on("exit", (code, signal) => code !== null ? process.exit(code) : signal !== null ? process.kill(process.pid, signal) : fail("Impossible situation, process exited but neither exited nor was killed")). I can't really use this in the general case, because I may need to do more stuff while the child process is running and exiting, and can't always assume the parent needs to die precisely when this one specific child process dies. At the same time the parent should be free to exit when all children are dead, and shouldn't hang like this.

@masaeedu
Copy link
Author

masaeedu commented Nov 12, 2018

I tried manually unpipe-ing stdin in the on("exit", ...) handler, in the hopes that this would fix the problem, but neither process.stdin.unpipe(child.stdin) nor process.stdin.unpipe(undefined) seem to make any difference.

@Trott
Copy link
Member

Trott commented Nov 13, 2018

@nodejs/child_process

@Trott Trott added the child_process Issues and PRs related to the child_process subsystem. label Nov 13, 2018
@santigimeno
Copy link
Member

Why not just call: process.stdin.unref() ?

@bnoordhuis
Copy link
Member

^ This. It's not a bug, it's a ps quirk. cat | ps works the same way.

@masaeedu
Copy link
Author

masaeedu commented Nov 13, 2018

@bnoordhuis If ps is quirky so is scp, because that also hangs the parent process (in fact my actual use case was uploading several files to a remote ssh server):

#!/usr/bin/env node
const util = require("util");
const cp = require("child_process");

const exe = "scp";
const args = [
  "-o",
  "StrictHostKeyChecking=no",
  "-o",
  "LogLevel=ERROR",
  "-i",
  "~/.ssh/test_machine_rsa",
  "-r",
  "test.js",
  "Administrator@192.168.33.164:C:/test.txt",
];

const { stdin, stdout, stderr } = process;
const child = cp.spawn(exe, args, {
  stdio: ["pipe", "pipe", "pipe"],
});

process.stdin.pipe(child.stdin); // this is the problematic one
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);

child.on("exit", (code, signal) => {
  console.log({ msg: "Exited", code, signal });
});

Maybe the quirk common to both is that neither actually consumes anything from stdin.

@bnoordhuis
Copy link
Member

Maybe the quirk common to both is that neither actually consumes anything from stdin.

That's right; cat | true is another example. I mentioned ps because you did. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
child_process Issues and PRs related to the child_process subsystem. invalid Issues and PRs that are invalid.
Projects
None yet
Development

No branches or pull requests

4 participants