-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
tty: add ref() so process.stdin.ref() etc. work #7360
Conversation
IIRC when I last tried this it didn't actually undo the weak reference.. |
It works for me with this test script: "use strict";
process.stdout.write("Keep Node open [y/N]?: ");
process.stdin.on("readable", function() {
var data = process.stdin.read();
if (data === null) {
return;
}
if (data[0] === "Y".charCodeAt(0) || data[0] === "y".charCodeAt(0)) {
process.stdin.ref();
} else {
process.stdin.unref();
process.stdout.write("There will be a 5-second delay for you to change your mind.\n");
setTimeout(function(){}, 5000);
}
process.stdout.write("Keep Node open [y/N]?: ");
});
process.on("exit", function(){ process.stdout.write("\n") }); AFAICT, I can't work something like this into the automated tests, but if there's a way to do so, I can try; just point me in the right direction. Re the CI, is there something that requires my action? I realise it's not passing, but I'm not sure what all the failures are. I do know one test was failing before I made my changes, and I rebased before submitting the PR, somewhat blindly following the instructions in the Contributing document, as I'm somewhat a Git n00b. Should I rebase my branch onto a commit where all the tests are passing? Or is there something else I should do? There seem to also be linting problems showing up in Jenkins which I doubt have anything to do with this change, but I'm not sure how to get more detailed information to even find out. I'm happy to do whatever I can, but I'll need a little guidance to know what to do. |
Ok, there is a way to make the test work and I did verify that it works correctly. Put this is 'use strict';
require('../common');
const TTY = process.binding('tty_wrap').TTY;
const handle = new TTY(0);
handle.readStart();
handle.unref();
handle.ref();
handle.unref(); |
Thanks. That was the start I needed. Looking at the code you provided, though, it only truly tests unref(): ref() could be a no-op and the test would still pass (unless it did something like throw, as it used to, but testing it doesn't throw is covered by the test I already provided). I've reworked it to use an unref()'d timeout to check that ref() does indeed keep Node running, so works as expected. If it doesn't, the timeout won't keep Node open either so there will be no output. Of course this also tests unref() works, because otherwise Node would hang and not exit at all.
Is there anything more I need to do here? |
Refs: nodejs#7360 PR-URL: nodejs#7613 Reviewed-By: Colin Ihrig <[email protected]>
test-tty-wrap hasn’t worked since StreamBase was introduced, I think. test-tty-stdout-end also happens to works with PipeWrap-s. Refs: nodejs#7360 PR-URL: nodejs#7613 Reviewed-By: Colin Ihrig <[email protected]>
test/parallel/test-tty-ref.js
Outdated
var handle = new TTY(1); | ||
|
||
handle.unref(); | ||
handle.ref(); // Should not throw. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this test - it will always be skipped and is therefore not useful. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(pseudo-tty/
tests are runs as party of normal test runs)
Looking good, CI: https://ci.nodejs.org/job/node-test-pull-request/3242/ |
Refs: #7360 PR-URL: #7613 Reviewed-By: Colin Ihrig <[email protected]>
test-tty-wrap hasn’t worked since StreamBase was introduced, I think. test-tty-stdout-end also happens to works with PipeWrap-s. Refs: #7360 PR-URL: #7613 Reviewed-By: Colin Ihrig <[email protected]>
@insightfuls Looks like lots of errors:
@cjihrig Any idea? I'm not really sure why @insightfuls Maybe it would better to use Colin's suggestion for testing this. |
That's strange. Nothing really jumps out, and it passes locally on my mac. |
Same, it also passes locally for me. |
I’d assume the reason it fails on CI is that standard input ends immediately there, and so the TTY handle tries to call I am able to reproduce the failure using diff --git a/test/pseudo-tty/ref_and_unref.js b/test/pseudo-tty/ref_and_unref.js
index 0faad3c..2131546 100644
--- a/test/pseudo-tty/ref_and_unref.js
+++ b/test/pseudo-tty/ref_and_unref.js
@@ -4,6 +4,7 @@ require('../common');
const TTY = process.binding('tty_wrap').TTY;
const handle = new TTY(0);
+handle.onread = () => {};
handle.readStart();
handle.unref(); |
f28da90
to
f875576
Compare
Ugh. I've updated my test case. I've opted for the internal timer approach, as I feel that tests precisely what I want it to test. I don't believe it will be flakey because it's not truly about time, it's only about giving the event loop an opportunity to tick over. But if any of you folk disagree, just see out the debate to get some consensus, and I'll be happy to follow it! Additionally, though, the active handle aspect is, I believe, tested by 'test-handle-wrap-isrefed-tty', which I found in 'parallel', and wouldn't have been working, because it spawned a subprocess with piped stdio, so was really testing pipe-wrap not tty-wrap. I've moved it to pseudo-tty and removed the spawning so it truly tests TTYs now. I've followed the pattern from #7613, doing the rename in a separate commit from fixing up the test. Please see updated branch! |
I'm still -1 on using a timer that isn't really needed. If a ref'ed handle doesn't keep the event loop open, then Node is completely broken. Thoughts from @nodejs/testing? |
Crap. I forgot about that one when I fixed the others recently...
hmmm... I forgot about that. It should be possible to make it also get a fake stdin. |
CI Again: https://ci.nodejs.org/job/node-test-pull-request/3335/ I like this, but I'm fine switching to @cjihrig's way. |
I've added a commit that adjusts all the |
strictEqual(Object.getPrototypeOf(timer._handle).hasOwnProperty('hasRef'), | ||
true, 'timer_wrap: hasRef() missing'); | ||
strictEqual(timer._handle.hasRef(), | ||
false, 'timer_wrap: unref() ineffective'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: There was no unref
before this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there was; it's just a line further up.
Apparently timers don't have _handle
defined prior to unref()
being called, so we cannot check hasRef()
exists, nor assert an initially refed
state for them. Instead we check the existence of hasRef()
and the unrefed
state after already calling unref()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh cool. Thanks for clarifying :-)
Why |
@thefourtheye The test runner expects them, |
Oh okay. Thanks @addaleax :-) |
(Just fixed up the author of the commit.) |
@insightfuls Are you sure you didn’t mean the committer of the commit? It might be splitting hairs but I’d like to be sure which email you actually wanted since you explicitly brought it up ( edit: this is the last thing I’d like to clear up before landing this ;) |
It doesn't really matter, but the github one is what I intended, and I figured it is probably more sensible if it's at least consistent for the related commits. |
Landed in 3c92200 🎉 Thanks for the PR! |
Also squashed from: * test: move tty-wrap isrefed test to pseudo-tty/ * test: test tty-wrap handle isrefed properly * test: improve failure messages in isrefed tests PR-URL: #7360 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: James M Snell <jasnell.gmail.com> Reviewed-By: Jeremiah Senkpiel <[email protected]>
Thanks a lot! |
Also squashed from: * test: move tty-wrap isrefed test to pseudo-tty/ * test: test tty-wrap handle isrefed properly * test: improve failure messages in isrefed tests PR-URL: #7360 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: James M Snell <jasnell.gmail.com> Reviewed-By: Jeremiah Senkpiel <[email protected]>
In hindsight, this shouldn't have this been either: |
Notable changes: * doc: add `Daijiro Wachi` to collaborators (Daijiro Wachi) nodejs/node#11676 * tty: add ref() so process.stdin.ref() etc. work (Ben Schmidt) nodejs/node#7360 * util: fix inspecting symbol key in string (Ali BARIN) nodejs/node#11672 PR-URL: nodejs/node#11745 Signed-off-by: Ilkka Myller <[email protected]>
Notable changes: * doc: add `Daijiro Wachi` to collaborators (Daijiro Wachi) nodejs#11676 * tty: add ref() so process.stdin.ref() etc. work (Ben Schmidt) nodejs#7360 * util: fix inspecting symbol key in string (Ali BARIN) nodejs#11672 PR-URL: nodejs#11745
Should this be backported? |
ping |
Should this be backported to v6.x-staging? If yes please follow the guide and raise a backport PR, if no let me know or add the |
ping re: backport |
Checklist
make -j4 test
(UNIX) orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
tty
Description of change
tty.ReadStream and tty.WriteStream are documented to be net.Socket subclasses, so should support unref() and ref(), but only unref() worked. I ran into this problem when following advice at http://stackoverflow.com/questions/26004519/why-doesnt-my-node-js-process-terminate-once-all-listeners-have-been-removed to get Node to exit when I stop listening to stdin (which seems to be delayed until a newline is received otherwise). If I changed my mind and wanted to start listening again prior to exiting, it wasn't possible as ref() wasn't implemented (net.Socket.ref threw when trying to call tty_wrap.ref which didn't exist). This fixes it up trivially by implementing tty_wrap.ref().