-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
stdio buffered writes (chunked) issues & process.exit() truncation #6456
Comments
Perhaps a list of issues this would address and/or close would be helpful to include since this seems to be a sprawling issue with a lot of fragmented discussion. |
Yes, just a little late in Europe :( keep 'em coming and I add them above. |
Also see #6410 |
Considering all the clarification in the #6410, is there also a theoretical possibility that not only several I/O calls to stdout could not make it, but even one simple |
@vsemozhetbyt that is especially correct if I'm understanding your question correctly. |
@vsemozhetbyt If it’s big enough, definitely. See e.g. test/known_issues/test-stdout-buffer-flush-on-exit.js. |
@vsemozhetbyt This output is truncated with node 6.0.0 on Mac after approx 40 lines:
node 5.x and earlier output all 40000 lines on Mac. |
So now if user does not want to reflow the code all one has is to write something like const err = {name: 'Error', message: 'something wrong'};
throw err; instead of console.log('Error: something wrong');
process.exit(1); and to deal with all the uncontrolled clutter of debug output? |
For dev code, sure, but uncaught exceptions in production code is not very elegant or professional. |
Related: #6379 Also discusses |
added @chalkers thread and updated this issue with some summaries and stuff. |
Not sure what you're talking about. #!/usr/bin/env bash
. ~/.nvm/nvm.sh
uname -a
echo
function do_buffer_test {
node <<< 'console.log((new Array(40000)).join("Hello! this is a test!\n"));' | wc -l
node <<< 'console.log((new Array(40000)).join("Hello! this is a test!\n")); process.exit(1)' | wc -l
node <<< 'console.log((new Array(40000)).join("Hello! this is a test!\n")); process.reallyExit(1)' | wc -l
node <<< 'console.log((new Array(40000)).join("Hello! this is a test!\n")); process.abort()' | wc -l
node <<< 'for (var i = 0; i < 40000; i++) console.log("Hello! this is a test!");' | wc -l
node <<< 'for (var i = 0; i < 40000; i++) console.log("Hello! this is a test!"); process.exit(1)' | wc -l
node <<< 'for (var i = 0; i < 40000; i++) console.log("Hello! this is a test!"); process.reallyExit(1)' | wc -l
node <<< 'for (var i = 0; i < 40000; i++) console.log("Hello! this is a test!"); process.abort()' | wc -l
}
nvm install 0.10
do_buffer_test
nvm install 0.12
do_buffer_test
nvm install 1
do_buffer_test
nvm install 2
do_buffer_test
nvm install 3
do_buffer_test
nvm install 4
do_buffer_test
nvm install 5
do_buffer_test
nvm install 6
do_buffer_test $ ./test-buffers.sh
Darwin JunonBox.local 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64
v0.10.44 is already installed.
Now using node v0.10.44 (npm v2.15.0)
40000
40000
40000
40000
40000
40000
40000
40000
v0.12.13 is already installed.
Now using node v0.12.13 (npm v2.15.0)
40000
40000
40000
40000
40000
40000
40000
40000
iojs-v1.8.4 is already installed.
Now using io.js v1.8.4 (npm v2.9.0)
40000
2849
2849
2849
40000
40000
40000
40000
iojs-v2.5.0 is already installed.
Now using io.js v2.5.0 (npm v2.13.2)
40000
2849
2849
2849
40000
40000
40000
40000
iojs-v3.3.1 is already installed.
Now using io.js v3.3.1 (npm v2.14.3)
40000
2849
2849
2849
40000
40000
40000
40000
v4.4.3 is already installed.
Now using node v4.4.3 (npm v2.15.1)
40000
2849
2849
2849
40000
40000
40000
40000
v5.11.0 is already installed.
Now using node v5.11.0 (npm v3.8.6)
40000
2849
2849
2849
40000
40000
40000
40000
v6.0.0 is already installed.
Now using node v6.0.0 (npm v3.8.6)
40000
2849
2849
2849
40000
40000
40000
40000 $ ./test-buffers.sh
Linux -snip- 3.18.27 #1 SMP Wed Feb 17 01:14:23 UTC 2016 x86_64 GNU/Linux
######################################################################## 100.0%
Now using node v0.10.44 (npm v2.15.0)
Creating default alias: default -> 0.10 (-> v0.10.44)
40000
40000
40000
40000
40000
40000
40000
40000
######################################################################## 100.0%
Now using node v0.12.13 (npm v2.15.0)
40000
40000
40000
40000
40000
40000
40000
40000
Downloading https://iojs.org/dist/v1.8.4/iojs-v1.8.4-linux-x64.tar.gz...
######################################################################## 100.0%
Now using io.js v1.8.4 (npm v2.9.0)
40000
2849
2849
2849
40000
40000
40000
40000
Downloading https://iojs.org/dist/v2.5.0/iojs-v2.5.0-linux-x64.tar.xz...
######################################################################## 100.0%
Now using io.js v2.5.0 (npm v2.13.2)
40000
2849
2849
2849
40000
40000
40000
40000
Downloading https://iojs.org/dist/v3.3.1/iojs-v3.3.1-linux-x64.tar.xz...
######################################################################## 100.0%
Now using io.js v3.3.1 (npm v2.14.3)
40000
2849
2849
2849
40000
40000
40000
40000
Downloading https://nodejs.org/dist/v4.4.3/node-v4.4.3-linux-x64.tar.xz...
######################################################################## 100.0%
Now using node v4.4.3 (npm v2.15.1)
40000
2849
2849
2849
40000
40000
40000
40000
Downloading https://nodejs.org/dist/v5.11.0/node-v5.11.0-linux-x64.tar.xz...
######################################################################## 100.0%
Now using node v5.11.0 (npm v3.8.6)
40000
2849
2849
2849
40000
40000
40000
40000
Downloading https://nodejs.org/dist/v6.0.0/node-v6.0.0-linux-x64.tar.xz...
######################################################################## 100.0%
Now using node v6.0.0 (npm v3.8.6)
40000
2849
2849
2849
40000
40000
40000
40000 Looks to me whenever io.js forked is when this started happening. Perhaps @indutny can shed some light on the subject. |
Adding two other possibilities.
|
@Qix- @eljefedelrodeodeljefe Please understand that when you pipe the results you are changing the test. It follows a different code path in node and libuv. You have to observe it on the terminal. So in that regard, the test is more difficult to automate. I am observing this behavior of Mac OS X 10.9.5. The behavior is different on Mac and Linux. Mac stdout appears to have had blocking writes to the tty historically. See #6297 (comment) |
+1 for new function Actually may have to leave |
If memory serves right, and by looking at the results posted by @Qix- I think this is where things started to change: libuv/libuv@b197515 Because we started to open writable TTYs in non-blocking mode. Follow the commit trail for reasonin, reverting is not an option. |
Yes, and that particular commit also introduced the tty redirection bug in src/unix/tty.c that was fixed in libuv 1.9.0. |
@kzc your point being? |
Just adding weight to reverting is not an option. |
@saghul I will add that prior to the tty redirection fix, Mac stdout appeared to be blocking based on my observations with |
Can I suggest closing out all other issues with a "discussion continues in #6456" comment? |
+1 ... we don't need multiple issues covering the same thing. |
When set, an internal timer will be set that will exit the process at the given timeout. In the meantime, the registered listeners for process.on('exitingSoon') will be invoked and passed a callback to be called when the handler is ready for the process to exit. The process will exit either when the internal timer fires or all the callbacks are called, whichever comes first. This is an attempt to deal more intelligently with resource cleanup and async op completion on exit (see nodejs#6456).
See: #6477 |
@Trott Based on some of these recent issues/commits linking to here, I suspect it still is an issue. (I've long had to move on to fix async writes, since it was causing tests to fail.) |
Yes, I can confirm 10.6.0 still shows this issue. Simple repro: $ node -p 'process.stdout.write("x".repeat(5e6)); process.exit()' | wc -c
65536 |
1. Compute deathSignal correctly 2. Redirect output to tmp file. Very long piped strings sometimes get mishandled.
…ng process.stdout to blocking. See nodejs/node#6456 for a discussion of the issue and a version of the fix used here. Signed-off-by: mrickard <[email protected]>
It seems to me that the most viable path forward is the one outlined by @gireeshpunathil in this comment in an earlier issue. I propose closing this issue in favor of that one (so we at least can keep conversation all in one place) and add a |
`process.exit()` may not flush stdio, which in turn can lead to the loss of output. See nodejs/node#6456. This issue manifests with `max-failures should work` test being flaky, where we examine large output and it is sometimes truncated.
`process.exit()` may not flush stdio, which in turn can lead to the loss of output. See nodejs/node#6456. This issue manifests with `max-failures should work` test being flaky, where we examine large output and it is sometimes truncated.
Closing in favor of the conversation happen in #6379 |
`process.exit()` may not flush stdio, which in turn can lead to the loss of output. See nodejs/node#6456. This issue manifests with `max-failures should work` test being flaky, where we examine large output and it is sometimes truncated.
If this is currently breaking your program, please use this temporary fix:
process
As noted in #6297 async stdio will not be flushed upon immediate
process.exit()
. This may lay open general deficiencies around Cexit()
from C++ functions not being properly unwound and is probably not just introduced by latestlibuv
updates. It should be considered to add flushing, providing graceful exit and/or improving unwinding C++ stacks.cc @jasnell, @kzc, @Qix-, @bnoordhuis
Issues
Discussion has been already taking place at several places, e.g. #6297, #6456, #6379
Summaries of Proposals
process.stdout.flush()
process.setBlocking(true)
node --blocking-stdio
longjmp()
towards main at exit in C++process.exit()
/process.reallyExit()
to new methodos.exit()
panic()
- or c++throw
-like stack unwindingDiscussions by Author (with content)
@ChALkeR
I tried to discuss this some time ago at IRC, but postponed it for quite a long time. Also I started the discussion of this in #1741, but I would like to extract the more specific discussion to a separate issue.
I could miss some details, but will try to give a quick overview here.
Several issues here:
console.log
(e.g. calling it in a loop) could chew up all the memory and die — Why does node/io.js hang when printing to the console inside a loop? #1741, Silly program or memory leak? #2970, Strange memory leaks #3171.console.log
has different behavior while printing to a terminal and being redirected to a file. — Why does node/io.js hang when printing to the console inside a loop? #1741 (comment).As I understand it — the output has an implicit write buffer (as it's non-blocking) of unlimited size.
One approach to fixing this would be to:
For almost all cases, except for the ones that are currently broken, this would behave as a non-blocking buffer (because writes to the buffer are considerably faster than writes from the buffer to file/terminal).
For cases when the data is being piped to the output too quickly and when the output file/terminal does not manage to output it at the same rate — the write would turn into a blocking operation. It would also be blocking at the exit until all the data is written.
Another approach would be to monitor (and limit) the size of data that is contained in the implicit buffer coming from the async queue, and make the operations block when that limit is reached.
The text was updated successfully, but these errors were encountered: