Repository navigation
Forked child process not detaching on windows #5146
Description
Activity
- addedchild_processIssues and PRs related to the child_process subsystem.Issues and PRs related to the child_process subsystem.windowsIssues and PRs related to the Windows platform.Issues and PRs related to the Windows platform.
on Feb 9, 2016 As far as I can tell the expected default behavior of a child process created with child_process.fork, is to be able to run independently of the process that spawned it once the parent dies.
The documentation indeed uses the word "independent" but the intent is convey that the processes are independent instances of the runtime, not that they're exempt from normal process control. /cc @nodejs/documentation - that should probably be cleared up.
On Windows, the child processes that node spawns are part of the same process group unless
{ detached: true }is passed tochild_process.spawn().In detached mode, the child process is created with the
CREATE_NEW_PROCESS_GROUPandDETACHED_PROCESSflags set. See the documentation for thedetachedoption for a list of caveats.@nodejs/documentation- that should probably be cleared up.I'm on it @bnoordhuis
I'll have it done in the following days, & I'll consult @chrisdickinson before it goes into queue for aPRYeah, I suspected that was the case re detached. Upon further testing I've found that the reason passing detached into the fork options wasn't working for me originally is that
childProcess.spawn("node", ["child.js"], {detached:true, stdio:[0, 1, 2, 'ipc']}); or childProcess.fork("child.js", {detached:true})doesn't work on windows (the child process just doesn't spawn), whereas
childProcess.spawn("node", ["child.js"], {detached:true, stdio:['pipe', 'pipe', 'pipe', 'ipc']}); or childProcess.fork("child.js", {detached:true, silent:true});works fine. My guess would be that spawning a child process with inherited fd's and the detached flags crashes it?
I'm going to defer to @nodejs/platform-windows for that. The tests we have for that particular child_process+stdio pattern are disabled on Windows but I don't know the details.
eljefedelrodeodeljefe commented
on Feb 18, 2016 ContributorMore actionsI am currently researching on this. The standard behaviour on unices is only to do
setsid()but not ignoringSIGHUP. Meaning it terminates on closing the tty session. First, we could clear this up indocs, but anyhow we don't provide to possibility to opt-in for ignoringSIGHUP. That might be worth a PR tolibuvor implementing it injs, given that the programmer is expecting orphaned processes. What would you think @bnoordhuis ?I am researching this on windows, but isn't the
child_processautomatically detached by default on windows threading implementation?At least there it's dispatching
SIGHUPexplicitly.we don't provide to possibility to opt-in for ignoring SIGHUP
You can install a handler for it like this:
process.on('SIGHUP', () => {}); // ignore
FWIW, I don't think it's a good idea to mix that with
{ detached: true }somehow. They're orthogonal concepts.isn't the child_process automatically detached by default on windows threading implementation?
Depends on your definition of 'detached'. The Windows and POSIX process models are different enough that it's a bit of an apples vs. oranges comparison.
eljefedelrodeodeljefe commented
on Feb 18, 2016 ContributorMore actionsMy point would be to make it very explicit by providing some kind of
child_process.release()or{relase: true}option, like what I believegohas:process, err := os.StartProcess("/bin/sleep", []string{"/bib/sleep", "100"}, &attr) if err == nil { // It is not clear from docs, but Realease actually detaches the process err = process.Release(); if err != nil { fmt.Println(err.Error()) } } else { fmt.Println(err.Error()) }
Since there are a lot of SO questions and other discussions about this, that would ease it. Instead of using a state machine and a no-op.
Example taken from here
eljefedelrodeodeljefe commented
on Feb 19, 2016 ContributorMore actions@bnoordhuis tested the noop, and I believe it doesn't work:
This will close the child process anyhow (Mac OS X).
// child_detach_payload.js const cp = require('child_process') cp.fork("child_detach_payload.js", {detached:true})
// child_detach_payload.js process.on('SIGHUP', () => {}); // ingore parents close event setInterval(function() { console.log('-> detached program doing work here'); }, 1000)
You mean when you close the terminal? I think that's because of OS X-specific behavior where writing to the tty fails with EIO. Also, it's possible the stock terminal emulator hard-kills any processes.
eljefedelrodeodeljefe commented
on Feb 19, 2016 ContributorMore actionsHmm. Interesting. Could reproduce on ubuntu though. I'll have a deeper look into the sources. Once I am through with osx and linux, I'll test on windows.
I believe this can be closed since #5330 landed. We can reopen this if that assumption is incorrect.
- added a commit that references this issue
on Mar 31, 2023
As far as I can tell the expected default behavior of a child process created with child_process.fork, is to be able to run independently of the process that spawned it once the parent dies.
So if parents.js is executed, child.js should remain as an orphaned process after the parent exits. This works on Linux, but not on Windows.
Tested on Ubuntu 14.04.3 LTS and Windows 8.1
Using Node v5.5.0 and v0.10.25 (both tested on each platform)