-
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
child_process: fire close event from stdio #22892
Conversation
lib/internal/child_process.js
Outdated
@@ -379,6 +379,9 @@ ChildProcess.prototype.spawn = function(options) { | |||
|
|||
if (i > 0 && this.pid !== 0) { | |||
this._closesNeeded++; | |||
if (stream._events && stream._events.close) { | |||
stream.socket.addListener('close', stream._events.close); | |||
} |
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.
I think this would lead to the event handler being called with a wrong this
value, and I think this might not work if there is more than one listener (because stream._events.close
would be an array then).
Could we use the listener in the lines below, and call stream.emit('close')
from there?
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.
I see. It might not work when events is an array.
I want to fix.
createSocket
create new Socket object and sharing only handle of old socket.
Therefore, we can't call old close events.
How do i fix it best ?
https://github.com/nodejs/node/blob/5a3e445304f3920590b2ae1d1237fe7615572a44/lib/internal/child_process.js#L274
https://github.com/nodejs/node/blob/5a3e445304f3920590b2ae1d1237fe7615572a44/lib/internal/child_process.js#L377
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.
Therefore, we can't call old close events.
I’m not sure I understand this – Can you explain more? i.e. what wouldn’t work if we add stream.emit('close');
in the callback below?
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.
I was misunderstanding. It could use stream.emit('close')
, if new stream object have old stream object instead of having _events
.
I am going to fix.
if (stream._stdio) {
stream._stdio.emit('close');
}
handle: handle,
- _events: events
+ _stdio: stdio
@addaleax Hi! I fixed this code. Can you review it ? |
lib/internal/child_process.js
Outdated
@@ -379,6 +379,9 @@ ChildProcess.prototype.spawn = function(options) { | |||
|
|||
if (i > 0 && this.pid !== 0) { | |||
this._closesNeeded++; | |||
if (stream._stdio) { | |||
stream._stdio.emit('close'); | |||
} |
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.
Shouldn’t this go in the stream.socket.on('close', () => {
handler below?
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.
@addaleax I could do it. I fixed and push this code. Please check it.
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.
LGTM but we probably need to address one thing before this can finally be merged :)
@@ -926,7 +929,8 @@ function _validateStdio(stdio, sync) { | |||
acc.push({ | |||
type: 'wrap', | |||
wrapType: getHandleWrapType(handle), | |||
handle: handle | |||
handle: handle, | |||
_stdio: stdio |
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.
So … the code above (https://github.com/nodejs/node/pull/22892/files#diff-f45eb699237c2e38dc9b49b588933c11R923) reads like stdio
could be:
- A native stream handle
- An object with a
handle
property which is a native stream handle - An object with a
_handle
property which is a native stream handle
The path that is typically taken for e.g. net.Socket
s would be the third one, I think. We should probably look into deprecating at least the first two, but … all that’s a different story and not really for this PR.
What matters is that stdio
does not need to be any kind of particular object; most of the time, it’s a net.Socket
or similar, but it could also just be { handle: someNativeHandle }
. Even though that’s a bad idea imo, the code above points to this being a possibility. This means that the stream._stdio.emit()
call above might fail, because emit()
might not be available?
I guess a simple solution would be to turn the if (stream._stdio) {
conditional into if (stream._stdio && typeof stream._stdio.emit === 'function') {
?
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.
I see. I will fix other PR.
I came up with a way when object is pushed. How about this?
Should it be judged when emit()
?
const a = {
type: 'wrap',
wrapType: getHandleWrapType(handle),
handle: handle
};
if (typeof stdio.emit === 'function') {
a._stdio = stdio;
}
acc.push(a);
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.
Or how about if (stream._stdio instanceof EventEmitter)
?
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.
@koh110 I’m not sure. instanceof EventEmitter
is probably fine, too?
I would prefer for the _stdio
property to be present consistently, though – either it’s always there or always missing.
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.
@addaleax Yeah, you right. I completely agree. I was wrong.
I would prefer for the _stdio property to be present consistently,
I feel that if (stream._stdio && stream._stdio instanceof EventEmitter) {
is more meaningful than if(stream._stdio && typeof stream._stdio.emit === 'function') {
. EventEmitter
may be changed to WritableStream
. What do you think about it?
@addaleax I fixed it. Check please. |
@nodejs/child_process It needs another approval. Please review it. |
Anyone else approve ? |
@nodejs/child_process Can someone review this? |
(Also: @addaleax Can you confirm this LGTY still?) |
Test fails on Windows in CI: 00:36:32 not ok 64 parallel/test-child-process-server-close
00:36:32 ---
00:36:32 duration_ms: 0.152
00:36:32 severity: fail
00:36:32 exitcode: 1
00:36:32 stack: |-
00:36:32 internal/child_process.js:372
00:36:32 throw errnoException(err, 'spawn');
00:36:32 ^
00:36:32
00:36:32 Error: spawn ENOTSUP
00:36:32 at ChildProcess.spawn (internal/child_process.js:372:11)
00:36:32 at spawn (child_process.js:543:9)
00:36:32 at Server.net.createServer (c:\workspace\node-test-binary-windows\test\parallel\test-child-process-server-close.js:12:3)
00:36:32 at Server.emit (events.js:189:13)
00:36:32 at TCP.onconnection (net.js:1507:8)
00:36:32 ... |
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.
Test not passing on Windows...
@Trott I fixed test. I think Travis is failed, but it is only API rate limit. I passed this lint in local. ++node -p 'JSON.parse(process.argv[1])[0].url' '{
"message": "API rate limit exceeded for 35.239.89.243. (But here'\''s the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)",
"documentation_url": "https://developer.github.com/v3/#rate-limiting"
}' Would you execute CI? |
@Trott I fixed fluky test. I think server would close before client. |
@Trott I am sorry for taking up so much of your time. Please execute CI. I found out Sometimes this code returns spawn(process.execPath, ['-v'], {
stdio: ['ignore', conn, 'ignore']
}); I removed |
some test not passing but i think that it unconnected this fix.
|
Resume Build CI: https://ci.nodejs.org/job/node-test-pull-request/20176/ |
Why does it throw |
Windows accept only UV_TTY and UV_NAMED_PIPE... node/deps/uv/src/win/process-stdio.c Lines 408 to 418 in 0109e12
|
Whould |
Maybe someone on @nodejs/platform-windows can help out or at least give a nudge in the right direction? |
Passing sockets as stdio handles is not supported by libuv under Windows. The internet says it is possible, but that would require some nontrivial changes to libuv. Maybe the test can use named pipes? |
Yes! Named pipes seems working!! Thank you so much! @Trott @bzoz This commit skipped over my code. So, i modified a few line. Could you review and CI again? @addaleax |
CI: https://ci.nodejs.org/job/node-test-pull-request/21302/ @Trott Can your request-changes be dismissed if CI is green? |
Yes. |
Landed in 1133e0b, thanks for the PR! 🎉 |
PR-URL: #22892 Reviewed-By: Anna Henningsen <[email protected]>
PR-URL: nodejs#22892 Reviewed-By: Anna Henningsen <[email protected]>
PR-URL: #22892 Reviewed-By: Anna Henningsen <[email protected]>
PR-URL: #26604 Refs: #22892 (comment) Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Bartosz Sosnowski <[email protected]>
PR-URL: nodejs#26604 Refs: nodejs#22892 (comment) Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Bartosz Sosnowski <[email protected]>
PR-URL: #26604 Refs: #22892 (comment) Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Bartosz Sosnowski <[email protected]>
PR-URL: #26604 Refs: #22892 (comment) Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Bartosz Sosnowski <[email protected]>
PR-URL: #26604 Refs: #22892 (comment) Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Bartosz Sosnowski <[email protected]>
Event of close does not fire when giving for stdio option that type is wrap.
For example, if we set event listener to net.server and giving child_process, that events never fire.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes