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

child_process - windowsHide not working with detached: true #21825

Open
affanshahid opened this issue Jul 15, 2018 · 27 comments
Open

child_process - windowsHide not working with detached: true #21825

affanshahid opened this issue Jul 15, 2018 · 27 comments
Labels
help wanted Issues that need assistance from volunteers or PRs that need help to proceed. windows Issues and PRs related to the Windows platform.

Comments

@affanshahid
Copy link

  • Version: v10.6.0
  • Platform: Windows 10 64-bit
  • Subsystem: child_process

Running the following results in a command prompt popping up to run the command, and the output not being piped correctly.

const log = fs.openSync('./log.out', 'w');

const c = cp.spawn(
  'npm.cmd', 
  ['-g', 'ls', '--depth', '0'],
  {stdio: ['ignore', log, log], detached: true, shell: false, windowsHide: true}
);

Removing detached makes everything work just fine. But the command wont run if the parent dies, which is something I don't want in the actual scenario.

@ghost
Copy link

ghost commented Jul 15, 2018

Possibly related: #15217 (comment)

@bzoz
Copy link
Contributor

bzoz commented Jul 18, 2018

It looks like it is because npm.cmd is a shell script. So it gets a shell with a window. This code, which runs npm js file directly:

const log = require('fs').openSync('./log.out', 'w');

const c = require('child_process').spawn(
  'node.exe', 
  ['C:\\...\\node_modules\\npm\\bin\\npm-cli.js', '-g', 'ls', '--depth', '0'],
  {stdio: ['ignore', log, log], detached: true, shell: false, windowsHide: true}
);

acts as expected, no window is spawned.

@corneliuc
Copy link

corneliuc commented Jul 19, 2018

Hello,

I have the same problem.
In the below example, I want to respawn a node process with detached = true which will spawn another process of procdump. In this case, the window is popping out and I don't want this happening.
I've put windowsHide flag on true but is not working.

Could you please help me?

Example:
==nodeSpawn.js file
let child_process = require("child_process");
const nodePath = "C:\Program Files\nodejs\node.exe";
child_process.spawn(nodePath,['procDumpSpawn.js'],{
detached: true, //=>is working without detached true
stdio: 'ignore',
shell: false,
windowsHide: true
});

==procDumpSpawn.js file
let child_process = require("child_process");
const procDumpPath = "C:\procdump.exe";
child_process.spawn(procDumpPath, ['notepad'],{
stdio: 'ignore',
});
Run: node nodeSpawn.js

Corneliu,

@ledmirage
Copy link

same thing here on node v10.14.2
i am using spawn to launch external exe (rethinkdb) with detached = true, and console window is popping up even windowsHide is set to true.
is there any workaround for this?

@ryzokuken ryzokuken added the windows Issues and PRs related to the Windows platform. label Dec 29, 2018
@ryzokuken
Copy link
Contributor

/cc @nodejs/platform-windows @bzoz is this expected behavior?

@seishun
Copy link
Contributor

seishun commented Dec 29, 2018

Seems to be the expected behavior per @bzoz's comment.

@ledmirage
Copy link

per bzoz's comment, the original issue seems to be due to spawning a script, but if spawning an exe it shall be okay, but for my case i was indeed spawning an exe as well.
just as side note, if i use execFile there was no pop up, but i need to use spawn in order to have detacted option (because i want to prevent SIGINT from passing down to child process)

@bzoz
Copy link
Contributor

bzoz commented Jan 2, 2019

@ledmirage use shell: false option

@ledmirage
Copy link

@bzoz tried that as well, but the pop up is still there
i am testing on Windows 10.

this is the code snippet:
const subprocess = child_process.spawn(cmd, args, {
detached: true
, stdio: 'ignore'
, shell: false
});

@bzoz
Copy link
Contributor

bzoz commented Jan 3, 2019

@ledmirage: what is your exact Node version and what exactly are you trying to run?

@ledmirage
Copy link

@bzoz i tried node 10.15 for windows
as mentioned i was running rethinkdb.exe (https://rethinkdb.com/docs/install/windows/)

@bzoz
Copy link
Contributor

bzoz commented Jan 7, 2019

Looks like this rethinkdb just needs some console for output. If you set stdio option to inherit or pipe the window will not appear.

Anyway, all this should be documented and added to windowHide option description.

@ledmirage
Copy link

@bzoz tried both inherit and pipe and together with windowsHide = true, still no luck
i will probably just accept this for now if no workaround

@bzoz
Copy link
Contributor

bzoz commented Jan 8, 2019

@ledmirage sorry to hear that. It worked for me though, maybe there is something in your app that affects this?

Could you verify that a simple script with only the spawn command still exibits this behavior?

@takashi1kun
Copy link

similar problem here, but with shell:true detached:true windowHide: true
on linux no terminal is visible, on windows a cmd appears, and for some reason the process im spawning needs shell:true and detached:true to work, so shell:false is not a option

@GrimzEcho
Copy link

Here is a small example highlighting this issue. The example uses a Node script to spawn a Python script that loops for x seconds, writing the value of the counter to both the console and a file.

------------------counter.py---------------------------

import time
import os
import sys

limit = sys.argv[1] if len(sys.argv) >= 2 else 3
delay = 1

for i in range(1, int(sys.argv[1]) + 1):
    print(i)
    with open('tmp.txt', 'a') as f:
        f.write('{} '.format(i))
        f.flush()
        os.fsync(f.fileno())

    time.sleep(delay)

And here is the Node script that runs it

const spawn = require('child_process').spawn;

const spawnOptions = {
	cwd: __dirname,
	stdio: 'ignore',
	detached: true,
	shell: true,
	windowsHide: true
};

const cmd = 'python counter.py 5';
const args = [];


const child = spawn(cmd, [], spawnOptions);
child.unref();
console.log(`Child with pid ${child.pid} spawned`);

Case 1: options = {detached: true, shell: true, windowsHide: true}
Expected: Node starts, spawns the child and exits. The counter child does not show in a new console, but writes its values to the log file.
Actual: Node starts, prints out the child pid, then immediately exits. The counter script is executed in a visible terminal and the user can see the output of the print statements. The counter log file is also created with the same output.

Case 2: options = {detached: false, shell: true, windowsHide: true}
Expected: Node starts, spawns the child and prints a PID, then waits for the child to finish. The counter child does not create a new console window but does write to the log file.
Actual: A child process is created (Node print out "Child with pid xxx spawned"), but both Node and the child immediately exit without doing anything. There is no console, no output, and nothing written to the counter log file.

Case 3: options = {detached: false, shell: true, windowsHide: false}
Expected: Node starts, spawns the child, and waits for it to finish. The child launches in a visible console, and the results are printed to the console and written to the log file.
Actual: Node starts, spawns the child, and immediately exits. No console is shown, and the results and the log file is written to disk. The actual behavior of case 3 is the expected behavior of case 1.

Case 4: options = {detached: true, shell: false, windowsHide: true}
Expected: Uncertain. I do not know if a shell is required to pass command line arguments to an executable.
Actual: Node.js error: Error: spawn python counter.py 5 ENOENT

Case 5: options = {detached: true, shell: false, windowsHide: true}; cmd = 'python',
Expected: Node runs, spawns a child that does nothing, and exists. No window is shown.
Actual: Same as expected

Case 6: options = {detached: true, shell: false, windowsHide: false}
Expected: Same as case 4
Actual: Same as case 4

Case 3 produced the results that I expected for case 1.

Namely, that if I wanted to spawn a detached child process that would persist after Node exited, and would run in the background, I would use:

opts = {
   detached: false,  // wtf?
   shell: true, // also wtf?
   windowsHide: false
}

Which is the exact opposite of what the documentation says

There are a couple of other permutations that I didn't try, but for those that I did, almost none worked as expected. The most interesting were cases 2 and 3. Based on the documentation and my understanding of Windows, changing the windowsHide value should not have any impact on the behavior of the underlying script, only on whether any created consoles are hidden or not. However, it appears that it does have a bigger effect. When set to true, the child did not seem to function at all.

Environment:
Python 2.7
Windows Server 2016

@rynz
Copy link

rynz commented Jul 3, 2019

Similar problem here on Windows using electron and tested with nodejs to execute a .exe.

Example:

const { spawn } = require('child_process')
spawn('.\\foo\\bar.exe', ['--test'], { shell: true, detached: true, windowsHide: true })

@PabloSzx
Copy link

Any workaround?

@simonbuchan
Copy link

This annoyed me, so I tracked this down: detached and windowsHide are translated directly to libuvs UV_PROCESS_DETACHEDandUV_PROCESS_WINDOWS_HIDE`, which on windows are handled with:

https://github.com/libuv/libuv/blob/dc7c874660526e4ed70c7c7579b974283c9ad6e0/src/win/process.c#L1070-L1100

I was somewhat suspicious of the test for inherited fds disabling CREATE_NO_CONSOLE causing this issue when , but it has nothing to do with windows hide.

With some testing, CreateProcess() will not show a new console window with DETACHED_PROCESS regardless of CREATE_NO_WINDOW, even for other console apps like node.exe, except for cmd.exe. That's rather confusing! Presumably cmd.exe checks if it has a console and creates and attaches a new console window if it doesn't.

You can see this behavior in node as child_process.spawn('node', ['-e', 'setTimeout(console.log,5000)'], { detached: true, shell: false }) will launch the node process for 5 seconds in task manager, but not show a console, while with shell: true it will, even though both node.exe and cmd.exe will show a console by default if you start them from the Windows UI (e.g. with Win-R or start menu) - this is presumably because the UI uses CREATE_NEW_CONSOLE.

Bizarrely, the fix seems to be to launch with CREATE_NEW_CONSOLE and startup.wShowWindow = SW_HIDE, which creates the process with a new console, but hidden. You can't use CREATE_NEW_CONSOLE with DETACHED_PROCESS, but it seems to imply it, in that my parent process will exit before the child at least. It would be good to have someone test this with inherited handles etc. and see if there's some other problem using this?

@jasnell jasnell added the help wanted Issues that need assistance from volunteers or PRs that need help to proceed. label Jun 26, 2020
@azev
Copy link

azev commented Feb 20, 2021

I have the same issue.

https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

		CHILD_PROCESS.execSync(cmd, {
			detached: true,
			stdio: 'ignore',
			windowsHide: true
		})

@hacknaked
Copy link

This issue is really annoying and the ticket is still open after 3 years. Any update on this?

@lukehaas
Copy link
Contributor

lukehaas commented Dec 4, 2021

I've recently started seeing this after upgrading to node 16.9.1.

@Kischy
Copy link

Kischy commented Apr 26, 2022

This issue still persists.

@Naozumi520
Copy link

Pretty shocked that the question has been open for so long and no one cares.

@tniessen
Copy link
Member

Pretty shocked that the question has been open for so long and no one cares.

@Naozumi520 If you care about this issue, please consider working on it. That's how open-source, non-profit projects work.

#21825 (comment) by @simonbuchan looks like it might be a good starting point. That being said, other comments indicate that the issue might depend on the application being spawned.

clabroche added a commit to clabroche/stack-monitor that referenced this issue Jun 15, 2023
jtoar pushed a commit to redwoodjs/redwood that referenced this issue Jul 27, 2023
**Problem**
Storybook is showing an error message when you exit via a SIGINT. 

We have spent a few hours trying to understand why and work around this
with no success.

*Changes**
1. Conditionally disable the additional default signal listeners based
on the argv contents.
2. Emit a custom event on `process` to trigger the telemetry shutdown.

**Notes**
I'm not really proud of this PR. Disabling based on the contents of argv
isn't all that robust against false positives. Emitting a custom event
on `process` is not really supposed to be done - hence why TS is
complaining about the name of the signal.

This work has also highlighted that on my windows 11 machine the
background scripts are not firing... This was working when I updated the
span values to match those found to work in this PR comment
nodejs/node#21825 (comment) when
I reenabled windows telemetry. Maybe something has changed, maybe it's
version specific (os or node). This is an active nodejs issue so my
ability to solve this in redwood code is understandably limited.

Why isn't our CI finding this? We should investigate this too.

@jtoar Could you confirm on mac and windows that this PR prevents those
additional error messages from storybook. If you also have the time I'd
appreciate if you could check if the telemetry background job is firing
when you test on windows.

I'll test this on ubuntu locally.
jtoar pushed a commit to redwoodjs/redwood that referenced this issue Jul 27, 2023
**Problem**
Storybook is showing an error message when you exit via a SIGINT. 

We have spent a few hours trying to understand why and work around this
with no success.

*Changes**
1. Conditionally disable the additional default signal listeners based
on the argv contents.
2. Emit a custom event on `process` to trigger the telemetry shutdown.

**Notes**
I'm not really proud of this PR. Disabling based on the contents of argv
isn't all that robust against false positives. Emitting a custom event
on `process` is not really supposed to be done - hence why TS is
complaining about the name of the signal.

This work has also highlighted that on my windows 11 machine the
background scripts are not firing... This was working when I updated the
span values to match those found to work in this PR comment
nodejs/node#21825 (comment) when
I reenabled windows telemetry. Maybe something has changed, maybe it's
version specific (os or node). This is an active nodejs issue so my
ability to solve this in redwood code is understandably limited.

Why isn't our CI finding this? We should investigate this too.

@jtoar Could you confirm on mac and windows that this PR prevents those
additional error messages from storybook. If you also have the time I'd
appreciate if you could check if the telemetry background job is firing
when you test on windows.

I'll test this on ubuntu locally.
@markthree
Copy link

markthree commented Feb 25, 2024

I ran into this stale issue today.

When encountering .cmd (windows), we inevitably open the terminal.

In light of the discussion on the web, I think the simplest solution is to run an additional node child process.

for example ↓

// index.js
import { execa } from "execa";

// run node child_process 
const child_process = execa("node", ["cmd.js"], {
  stdio: "ignore",
  shell: false,
  detached: true,
  windowsHide: true,
});

// quick exit, don't lock the parent process
child_process.unref();
// cmd.js
import { execa } from "execa";
import { resolve } from "path";

// static is my cmd file
await execa("static", {
  cleanup: true,
  stdio: "inherit"
});

Finally, execute node index.js,Everything's hidden.

@huseyinacacak-janea
Copy link
Contributor

I’ve thoroughly investigated this issue. Given the complexity of these parameters, I thought it would be helpful to outline some basic rules:

  • When running a shell script, ensure that shell is set to true.
  • For the windowsHide option, please note that if detached is set to true or if the application is a console application, this option will be ignored. You can find more details here.
  • There are no restrictions for the detached option.

Based on this information, I have tested nearly every combination, and they all work as expected.
@affanshahid Do you think this issue could be closed now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Issues that need assistance from volunteers or PRs that need help to proceed. windows Issues and PRs related to the Windows platform.
Projects
None yet
Development

No branches or pull requests