Fix blocking / non-blocking stdio woes #3584

Closed
piscisaureus opened this Issue Jun 29, 2012 · 49 comments

Projects

None yet
@piscisaureus
Member

Currently process.stdin / stdout / stderr is blocking, except when it is a pipe on windows. Weird and surprising. Very unpractical in cases where stdio is used as an IPC mechanism between node processes.

Discussion:http://logs.nodejs.org/libuv/2012-06-29#00:40:38.256

Preliminary results: have process.stdout.setBlocking(true|false) or process.stdout.writeSync.

Feel free to post thoughts here.

@cowboy
cowboy commented Aug 26, 2012

I've experienced a similar issue with stdio in Windows, and have somewhat worked around it in the meantime with this horrible, horrible hack.

While my mini exit lib works well in place of process.exit in some cases, it completely fails to help in this case:

var exitHack = require('./exit').exit;

// If there are pending stdout / stderr writes when "condition" is met...
if (condition) {
  exitHack();
}

// ...this code will still do something. Whoops!
doSomething();

I haven't seen this problem in OS X or Linux. It would be great if Node.js behaved the same cross-OS.

@bpasero
bpasero commented Jan 17, 2013

Any update? Will this land in 0.10?

@isaacs
isaacs commented Mar 6, 2013

This issue has been stagnant for months. In order for this to happen, it will need a champion.

Are you that champion? Would you like to see stdio have a more consistently blocking/nonblocking interface, which works the same on Windows and Unix?

Heed the call. Build the bits that need to go into libuv. Sketch out an API in node for it.

It seems that it won't make the 0.10 cut-off, I'm afraid. Maybe next pass.

@HenryRawas

I have started to look into this issue. Here is what I have found so far.
If stdout is not piped, then the output goes through libuv tty code which is blocking as expected.
If stdout is piped, the output goes through libuv pipe code.
The pipe code checks to see if the pipe supports overlapped IO.
In the case of piped stdout it does not - NtQueryInformationFile returns a mode of FILE_SYNCHRONOUS_IO_NONALERT, which means:
All operations on the file are performed synchronously.
Wait requests in the system that must synchronize I/O queuing and completion are not subject to alerts
In this case the pipe code uses the thread pool to perform all IO.
So when the process exits, the write requests are queued up for the thread pool to execute, but they are never executed.

I made a quick hack to simply let the Write operations execute synchronously when the pipe is in this mode.
In the tests that I have, this fixes the problem of data being lost when the process exits.

This approach means that stdout would have blocking IO behavior even when piped, without requiring any new API.

Other pipes that have mode FILE_SYNCHRONOUS_IO_NONALERT or FILE_SYNCHRONOUS_IO_ALERT would also end up being blocking.
These modes may be set on a pipe or file when creating it, but libuv never sets it.

Does this seem like an acceptable way of fixing this issue?

@bpasero
bpasero commented May 29, 2013

Excellent! Any chance of getting this into node 0.10.x? This fix will allow me to get rid of ugly workarounds I need to use currently to not loose process output.

@bnoordhuis
Member

@piscisaureus and/or @sblom: request for comment, please.

@HenryRawas

Second pull request fixes commit message problems.

@sblom
sblom commented May 30, 2013

@HenryRawas works with me. I'll look at thiS.

@HenryRawas

Updated the proposed fix. Added API uv_pipe_setblocking() to libuv and changed windows pipe to use synchronous writes if this is set. Updated node code to call uv_pipe_setblocking() for stdio over pipe.

@bpasero
bpasero commented Jun 14, 2013

@HenryRawas is it realistic to get this fix in for 0.10.x?

@HenryRawas

I am still trying to get the change accepted. I don’t know where it will land.

From: Benjamin Pasero [mailto:notifications@github.com]
Sent: Friday, June 14, 2013 2:07 AM
To: joyent/node
Cc: Henry Rawas
Subject: Re: [node] Fix blocking / non-blocking stdio woes (#3584)

@HenryRawashttps://github.com/HenryRawas is it realistic to get this fix in for 0.10.x?


Reply to this email directly or view it on GitHubhttps://github.com/joyent/node/issues/3584#issuecomment-19446612.

@jdalton
jdalton commented Jun 27, 2013

Just wanted to 👍 this issue. Was just bit by it in Windows 8 with Node v0.10.12. I'm still looking for a workaround atm.

@dcherman

@jdalton Did you try the pipe to file workaround?

@jdalton
jdalton commented Jun 27, 2013

@dcherman No I haven't. Did I miss it already covered?

Here is what I'm trying to do. I noticed that the stdout output was truncated:

var foo = cp.spawn(fooPath, fooOptions);

var output = '';
foo.stdout.on('data', function(data) {
  output += data;
});

foo.on('exit', function() {
  fs.writeFileSync(outputPath, output, 'utf8');
});
@cowboy
cowboy commented Jun 27, 2013

No matter what, don't do string concat like that. Use Buffer instances and .concat them.

@jdalton
jdalton commented Jun 27, 2013

@dcherman Woo doing:

var logStream = fs.createWriteStream(outputPath);
foo.stdout.pipe(logStream);
foo.on('exit', function() {
  // do some cleanup
});

seems to work :)

@jdalton
jdalton commented Jun 28, 2013

Actually nix my issue. I tried it manually via the console and for some reason > isn't capturing all the stdout that's normally being displayed to the console. Looks like it's not a node issue.

@vladikoff

Anyone got any updates on this?

@bpasero
bpasero commented Aug 14, 2013

Will this fix Land in 0.12? I hear 0.12 is nearing completion.

@tonylukasavage

I promise to make grand offerings I'll never follow through on for whoever resolves this. Anybody else who experiences this in the meantime, fs.writeSync() worked well for me in my CLI tool. I just do this when I'm running my tests now on Windows and I always get my stdout/stderr back from exec() and spawn():

console.log = console.info = console.warn = function(m) {
    fs.writeSync(1, m);
};
console.error = function(m) {
    fs.writeSync(2, m);
};
@ghost
ghost commented Sep 8, 2013

Code Bounty

@feklee
feklee commented Sep 15, 2013

I ran into the issue when trying to execute Node code from Emacs on Windows. Apparently EShell, the built in shell, always uses piping for executing commands. So I didn't get output from ordinary Node apps, and I had to write wrappers, using temporary files.

Test case for cmd.exe (i.e. not Emacs' EShell):

  • hello.js:

    console.log('Hello world!');
    process.exit(5);
    
  • Run as: C:\>node hello.js | MORE

  • No output.

@elieux
elieux commented Sep 18, 2013

I got the same problem today and after a while of searching the nets, I got here. I'm confused though. Is this fixed? If yes, why is the patch not included in the release? If not, what is missing?

@seanmonstar

@elieux the issue is still open, so it's not likely fixed.

@vladikoff

Please test https://npmjs.org/package/exit from @cowboy for a possible solution to this issue. Thanks!

@bpasero
bpasero commented Sep 21, 2013

I don't see how that module would help unless all modules would adopt it.

@cowboy
cowboy commented Sep 21, 2013

Yeah, https://npmjs.org/package/exit is not a solution to the issue, it's just a possible workaround. I'm not even sure it works everywhere yet, but hey--that's what testing is for.

@OrenMe OrenMe referenced this issue in jonnyzzz/TeamCity.Node Sep 24, 2013
Open

Grunt log is truncated #29

@mrchief
mrchief commented Sep 25, 2013

👍

@vladikoff

exit 0.1.1 was just published: https://npmjs.org/package/exit
0.1.1 addresses some exit code issues has a few fixes.
Help test this workaround if you get a chance, thanks!

@vladikoff vladikoff referenced this issue in gruntjs/grunt Sep 29, 2013
Closed

Fixing process exit and output issues #921

@zhiwww
zhiwww commented Oct 13, 2013

node-exit is not working here. Win 7, node 0.10.20. Seems like the drain event has never been triggered, so the script never exits.

@refack
Member
refack commented Oct 13, 2013

@zhiwww same here (win8x64 / node 0.10.20x64)
I added a PR that solves it for me: cowboy/node-exit#3

@ErisDS ErisDS added a commit to ErisDS/Ghost that referenced this issue Nov 27, 2013
@ErisDS ErisDS Removing error handling using process.stderr
- process.stdin/out/error is problematic, see nodejs/node-v0.x-archive#3584
84ce7cc
@yeputons

@HenryRawas any news with this one?

@thasmo
thasmo commented Jan 19, 2014

@isaacs, @sblom, @HenryRawas - sorry for spamming - any updates on this? Thanks! :)

@Panya Panya referenced this issue in stylus/stylus Jan 22, 2014
Closed

version output race condition #1356

@korczis
korczis commented Feb 12, 2014

So any updates?

@nitroduna

So is it known that writing to stdout in unix/linux is blocking even when it refers to pipes?

After analyzing a logging issue in our code, I found out this behavior and today I wrote a post in the node google group: https://groups.google.com/d/msg/nodejs/Ua4nmiNPZXY/Vq3pepnM9Q8J

That behaviour is not consistent with the API documentation http://nodejs.org/api/process.html#process_process_stdout that says it is always non-blocking when stdout refers to a pipe.

I've just seen that the libuv code was fixed to make stdout writings non-blocking in linux joyent/libuv@8fe4ca6 but then it was reverted again to blocking mode joyent/libuv@8c9cbee

I suppose it was reverted because, as I can see in older comments, your are trying to make it work blocking in windows, but meanwhile I think the API documentation should be changed to reflect the actual behaviour, because the current one causes much confusion.

@nitroduna nitroduna referenced this issue in joyent/libuv Feb 12, 2014
@bnoordhuis bnoordhuis Revert "unix: set O_NONBLOCK in uv_pipe_open()"
It turns out that node.js relies on the blocking behavior of pipes in
some cases, notably when forking worker processes.  Reopens #941.

This reverts commit 8fe4ca6.
8c9cbee
@orangemocha orangemocha added a commit that closed this issue Feb 26, 2014
@orangemocha @tjfontaine orangemocha + tjfontaine src: make stdout/sterr pipes blocking
Expose `setBlocking` on Pipe's and if a pipe is being created for stdio
on windows then make the pipes blocking.

This fixes test-stream2-stderr-sync.js on Windows.

Fixes #3584
20176a9
@vladikoff

Well this is exciting, thanks @orangemocha

@dougwilson

And there was much rejoicing

@cowboy
cowboy commented Feb 26, 2014

omg

@fresheneesz

omg yay? Is it really happening?

@tonylukasavage

Glorious

@Bartvds
Bartvds commented Feb 26, 2014

Sweet!

@yeputons

Calm down, it's just a pull request :) Not merged yet.

@tjfontaine

On the contrary a different fix was landed. So there is reason to rejoice

@bajtos bajtos added a commit to strongloop/loopback-sdk-angular-cli that referenced this issue May 9, 2014
@bajtos bajtos Fix unit-tests failing on windows
Execute `node bin/lb-ng` instead of `bin/lb-ng`, because Windows does not
recognize hasbang notation.

Modify lb-ng to exit in the next tick, so that stdout & stderr are flushed
before exit (workaroud for nodejs/node-v0.x-archive#3584).
f917263
@RReverser RReverser added a commit to RReverser/acorn that referenced this issue Jul 24, 2014
@RReverser RReverser Workaround for nodejs/node-v0.x-archive#3584. 6ff004a
@marijnh marijnh added a commit to ternjs/acorn that referenced this issue Jul 29, 2014
@RReverser @marijnh RReverser + marijnh Workaround for nodejs/node-v0.x-archive#3584. 5ab6837
@markelog markelog added a commit to jscs-dev/node-jscs that referenced this issue Aug 31, 2014
@takueof @markelog takueof + markelog Avoid node.js 0.10.x exit code bug for MS Windows 98c08ed
@morficus morficus pushed a commit to morficus/Ghost that referenced this issue Sep 4, 2014
@ErisDS ErisDS Removing error handling using process.stderr
- process.stdin/out/error is problematic, see nodejs/node-v0.x-archive#3584
f741b35
@sonicdoe sonicdoe added a commit to sonicdoe/brave-mouse that referenced this issue Jan 31, 2015
@sonicdoe sonicdoe Use exit on Windows to ensure stdio is flushed c378c98
@avital avital added a commit to meteor/meteor that referenced this issue Feb 2, 2015
@avital avital Flush buffer on `process.exit` in Windows
This works around a bug that's present in Node
0.8 and 0.10. This will likely be fixed in 0.12.
nodejs/node-v0.x-archive#3584
ed06b75
@amavisca amavisca pushed a commit to jasmine/jasmine-npm that referenced this issue Feb 4, 2015
Christopher Amavisca Use exit module instead of process.exit for Windows workaround
- process.exit isn't properly waiting for buffers to finish writing in Windows
- issue in node fixed in v0.11.12: nodejs/node-v0.x-archive#3584

Fixes #20
92f47d3
@agebert agebert added a commit to e2ebridge/e2e-conf that referenced this issue Feb 6, 2015
@agebert agebert bug: Fix for Windows' drain error on process.exit (Issue 3584)
Output to stderr or stdout is not always completly written if
you exit the process. Issue happens only on Windows using pipes.

Issue nodejs/node-v0.x-archive#3584 will be fixed in
node.js 0.12.
9ac7558
@pmeijer pmeijer added a commit to webgme/webgme that referenced this issue Apr 6, 2015
@pmeijer pmeijer Add error-handling for rj-build gulp task.
This is currently not working, awaits nodejs/node-v0.x-archive#3584
4071833
@samuelbjohnson samuelbjohnson referenced this issue in RetireJS/retire.js Apr 30, 2015
Merged

Fix console.error process.exit flush issue #88

@pgilad
pgilad commented May 26, 2015

Hi, is this considered resolved? Is the use of https://github.com/cowboy/node-exit still recommended for some versions of node?

@orangemocha
Member

Yes, it is resolved. It was fixed with 20176a9.
You shouldn't need the workaround anymore.

@pgilad
pgilad commented May 26, 2015

Great, thanks!

@gigapromoters

Issue still exists for me in 0.12.4, Windows 8.1:

var child = require('child_process').spawn('php',
['-S', 'localhost:8007']);
child.stdout.on('data', function(data) {
console.log("child: "+data.toString());
});

Not sure if this is a bug, but if the process is infinite - then the child.stdout's callback is never triggered.

@gigapromoters

I wrapped php process in another child script, now it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment