-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
inspector: allow concurrent inspector sessions #20137
Conversation
CI: https://ci.nodejs.org/job/node-test-pull-request/14366/ (note there might be platform-specific issues, I will be looking into them) |
Generally good with this, haven't reviewed the code yet so won't sign off just yet. But, I wanted to ask if you could articulate some of the issues that could present with this. For instance, suppose I have two concurrent sessions open... is it possible for one to interfere with the other? For instance, what impact does setting a breakpoint in one session have on the other? Can there be hidden side effects? |
@jasnell there are many edge cases, and that is expected... The main use-case had been to allow different tools use different "domains" concurrently - e.g. some IDE would connect to Chrome for debugging, while Chrome DevTools can still be used to inspect DOM. For Node, this should allow debuginng the application that uses the
|
Another CI run, I had a bad testcase in the original version: https://ci.nodejs.org/job/node-test-pull-request/14367/ |
1 and 2 are the concerns for me. What we'll end up with are pauses in one frontend that happens for no obvious reason. What I'd like to make sure of is that when the pause is reported, there is enough context included for one frontend to know that the pause originated in a concurrently connected session so at least there's the ability to reason about it. If that's already accounted for, then awesome, never mind me :-) |
@jasnell this isn't that different from the |
Found a bug in V8 inspector around multisession support. Updated this PR with a workaround for a said bug. New CI: https://ci.nodejs.org/job/node-test-pull-request/14373/ |
@eugeneo ... thank you for the additional detail. As I've said I'm generally good with this I just want to make sure we have a good idea of what issues may come up with this. Any time we get into multi-session anything, especially with single loop, there are bound to be issues ;-) . Thank you for doing 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.
Generally LGTM but would love @addaleax and @bnoordhuis to take a look :-)
CI for a new version: https://ci.nodejs.org/job/node-test-pull-request/14386/ |
CI mostly green, looks like MacOS CI is busted and failes on all changes. There are no inspector-specific test failures. |
new ChannelImpl(client_.get(), delegate)); | ||
int connectFrontend(std::unique_ptr<InspectorSessionDelegate> delegate) { | ||
events_dispatched_ = true; | ||
int session_id = next_session_id_++; |
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.
Is it possible for this to have a race condition (e.g. WebSocket server and a JS inspector session launching at the same time)?
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.
All API in this file are called only from the main thread. E.g. incoming WS session will "interrupt" V8 (or will use uv_async_t) before calling this function.
src/inspector_agent.cc
Outdated
// There is a bug in inspector that causes every session | ||
// call V8InspectorClient::quitMessageLoopOnPause. We are using this flag | ||
// to ignore those calls so message loop is spinning as long as there's a | ||
// reason to expect inspector messages |
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.
Is there a crbug for 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.
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.
Can you put that link in the comment?
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 added it in a separate commit, will squash before merging.
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.
Left some suggestions for improvements but LGTM either way.
src/inspector_agent.cc
Outdated
events_dispatched_ = true; | ||
int session_id = next_session_id_++; | ||
channels_[session_id] = | ||
std::make_unique<ChannelImpl>(client_.get(), std::move(delegate)); |
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.
client_.get()
looks kind of questionable. Could it be turned into a std::shared_ptr
?
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 do not want to imply shared ownership. I changed the code to use const std::unique_ptr&.
src/inspector_agent.cc
Outdated
std::unordered_map<void*, InspectorTimerHandle> timers_; | ||
int next_session_id_; | ||
bool events_dispatched_; |
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.
bool events_dispatched_ = false;
?
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.
Changed this and other similar fields.
src/inspector_agent.cc
Outdated
std::unique_ptr<InspectorSession> Agent::Connect( | ||
std::unique_ptr<InspectorSessionDelegate> delegate) { | ||
int session_id = client_->connectFrontend(std::move(delegate)); | ||
return std::make_unique<InspectorSession>(session_id, client_.get()); |
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.
Maybe turn client_
into a std::shared_ptr
?
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.
Did that.
src/inspector_js_api.cc
Outdated
session->CheckIsCurrent(); | ||
Agent* inspector = env->inspector_agent(); | ||
inspector->Dispatch(ToProtocolString(env->isolate(), info[0])->string()); | ||
if (session->session_) |
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.
Can you put braces around the body?
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.
Done
src/inspector_js_api.cc
Outdated
Persistent<Function> callback_; | ||
}; | ||
|
||
static bool InspectorEnabled(Environment* env) { | ||
Agent* agent = env->inspector_agent(); | ||
return !!agent->io() || agent->HasConnectedSessions(); |
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.
Can you do an explicit nullptr check instead of coercing to bool?
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.
Done
}, 150); | ||
session.on('Debugger.paused', () => { | ||
session.disconnect(); | ||
process.exit(0); |
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.
It would be infinitesimally nicer to have node exit naturally by calling clearInterval(interval)
.
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.
Done
Thank you for the reviews, I addressed the comments. I will merge this PR after the weekend. |
Relevant macOS test failure: https://ci.nodejs.org/job/node-test-commit-osx/17976/nodes=osx1010/console not ok 1107 parallel/test-inspector-multisession-ws
---
duration_ms: 0.330
severity: fail
exitcode: 1
stack: |-
[test] Connecting to a child Node process
[test] Testing /json/list
[test] Connecting to a child Node process
[test] Testing /json/list
[err] Debugger listening on ws://127.0.0.1:50554/d51f55a4-567c-49b0-89cd-669ce131d100
[err] For help, see: https://nodejs.org/en/docs/inspector
[err]
{ Error: write EPIPE
at WriteWrap.afterWrite [as oncomplete] (net.js:836:14) errno: 'EPIPE', code: 'EPIPE', syscall: 'write' }
1
... |
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.
Blocking on the test failure. Feel free to clear this if the test has been fixed.
Test failure is caused by #20254, I would like to land that PR before landing this one. |
This change enables concurrent inspector sessions, through WebSocket interface as well as JS interface, in any combination. PR-URL: #20137
Rebased, squashed the commits, CI is green: https://ci.nodejs.org/job/node-test-commit/18054/ @Trott - please take another look. |
Given this from statement @Trott:
Since the CI is green now, I think it is reasonable to dismiss that review. |
Landed as 1300103 |
Just got this CI failure for an AIX stress-test run: https://ci.nodejs.org/job/node-stress-single-test/1825/nodes=aix61-ppc64/console It seems related to this PR? Not sure why it wouldn’t show up in regular CI… |
I think because the stress job isn't using the compiler selector script added by nodejs/build#1240 so it's using the wrong level of gcc. cc @nodejs/build @mhdawson |
e.g., https://ci.nodejs.org/job/node-stress-single-test/1825/nodes=aix61-ppc64/consoleFull
We should be using gcc 6.3 on AIX for v10.x and master as per nodejs/build#1240. |
Should I remove |
@eugeneo I believe it's an infrastructure issue with the stress job not using the correct level of C++ compiler on AIX (the normal CI jobs should be fine). This PR is the first change that's actually caused the build to fail on older compilers (where previously you would be warned but the build would succeed), but there's a reason we specify the supported toolchains. |
@richardlau Ok, thanks. Ping me if this needs to be fixed - this is a trivial change. |
This change enables concurrent inspector sessions, through WebSocket interface as well as JS interface, in any combination. PR-URL: #20137 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
This change enables concurrent inspector sessions, through WebSocket
interface as well as JS interface, in any combination.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes