Skip to content

Commit 23119ca

Browse files
alexkozytargos
authored andcommitted
inspector: supported NodeRuntime domain in worker
NodeRuntime domain was introduced to give inspector client way to fetch captured information before Node process is gone. We need similar capability for work. With current protocol inspector client can force worker to wait on start by passing waitForDebuggerOnStart flag to NodeWorker.enable method. So client has some time to setup environment, e.g. start profiler. At the same time there is no way to prevent worker from being terminated. So we can start capturing profile but we can not reliably get captured data back. This PR implemented NodeRuntime.notifyWhenWaitingForDisconnect method for worker. When NodeRuntime.waitingForDisconnect notification is enabled, worker will wait for explicit NodeWorker.detach call. With this PR worker tooling story is nicely aligned with main thread tooling story. The only difference is that main thread by default is waiting for disconnect but worker thread is not waiting. Issue: #27677 PR-URL: #27706 Reviewed-By: Eugene Ostroukhov <[email protected]>
1 parent 6a5ce36 commit 23119ca

File tree

6 files changed

+70
-10
lines changed

6 files changed

+70
-10
lines changed

src/inspector/node_protocol.pdl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ experimental domain NodeWorker
7171
# Detaches from all running workers and disables attaching to new workers as they are started.
7272
command disable
7373

74+
# Detached from the worker with given sessionId.
75+
command detach
76+
parameters
77+
SessionID sessionId
78+
7479
# Issued when attached to a worker.
7580
event attachedToWorker
7681
parameters

src/inspector/runtime_agent.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ void RuntimeAgent::Wire(UberDispatcher* dispatcher) {
1616
}
1717

1818
DispatchResponse RuntimeAgent::notifyWhenWaitingForDisconnect(bool enabled) {
19-
if (!env_->owns_process_state()) {
20-
return DispatchResponse::Error(
21-
"NodeRuntime domain can only be used through main thread sessions");
22-
}
2319
notify_when_waiting_for_disconnect_ = enabled;
2420
return DispatchResponse::OK();
2521
}

src/inspector/worker_agent.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ DispatchResponse WorkerAgent::disable() {
115115
return DispatchResponse::OK();
116116
}
117117

118+
DispatchResponse WorkerAgent::detach(const String& sessionId) {
119+
workers_->Detached(sessionId);
120+
return DispatchResponse::OK();
121+
}
122+
118123
void NodeWorkers::WorkerCreated(const std::string& title,
119124
const std::string& url,
120125
bool waiting,

src/inspector/worker_agent.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class WorkerAgent : public NodeWorker::Backend {
2525

2626
DispatchResponse enable(bool waitForDebuggerOnStart) override;
2727
DispatchResponse disable() override;
28+
DispatchResponse detach(const String& sessionId) override;
2829

2930
private:
3031
std::shared_ptr<NodeWorker::Frontend> frontend_;

src/inspector_agent.cc

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,8 @@ class NodeInspectorClient : public V8InspectorClient {
472472
runMessageLoop();
473473
}
474474

475-
void waitForIoShutdown() {
476-
waiting_for_io_shutdown_ = true;
475+
void waitForSessionsDisconnect() {
476+
waiting_for_sessions_disconnect_ = true;
477477
runMessageLoop();
478478
}
479479

@@ -548,6 +548,8 @@ class NodeInspectorClient : public V8InspectorClient {
548548
}
549549
contextDestroyed(env_->context());
550550
}
551+
if (waiting_for_sessions_disconnect_ && !is_main_)
552+
waiting_for_sessions_disconnect_ = false;
551553
}
552554

553555
void dispatchMessageFromFrontend(int session_id, const StringView& message) {
@@ -678,8 +680,9 @@ class NodeInspectorClient : public V8InspectorClient {
678680
bool shouldRunMessageLoop() {
679681
if (waiting_for_frontend_)
680682
return true;
681-
if (waiting_for_io_shutdown_ || waiting_for_resume_)
683+
if (waiting_for_sessions_disconnect_ || waiting_for_resume_) {
682684
return hasConnectedSessions();
685+
}
683686
return false;
684687
}
685688

@@ -723,7 +726,7 @@ class NodeInspectorClient : public V8InspectorClient {
723726
int next_session_id_ = 1;
724727
bool waiting_for_resume_ = false;
725728
bool waiting_for_frontend_ = false;
726-
bool waiting_for_io_shutdown_ = false;
729+
bool waiting_for_sessions_disconnect_ = false;
727730
// Allows accessing Inspector from non-main threads
728731
std::unique_ptr<MainThreadInterface> interface_;
729732
std::shared_ptr<WorkerManager> worker_manager_;
@@ -819,11 +822,14 @@ void Agent::WaitForDisconnect() {
819822
fprintf(stderr, "Waiting for the debugger to disconnect...\n");
820823
fflush(stderr);
821824
}
822-
if (!client_->notifyWaitingForDisconnect())
825+
if (!client_->notifyWaitingForDisconnect()) {
823826
client_->contextDestroyed(parent_env_->context());
827+
} else if (is_worker) {
828+
client_->waitForSessionsDisconnect();
829+
}
824830
if (io_ != nullptr) {
825831
io_->StopAcceptingNewConnections();
826-
client_->waitForIoShutdown();
832+
client_->waitForSessionsDisconnect();
827833
}
828834
}
829835

test/parallel/test-worker-debug.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,52 @@ async function testTwoWorkers(session, post) {
206206
await Promise.all([worker1Exited, worker2Exited]);
207207
}
208208

209+
async function testWaitForDisconnectInWorker(session, post) {
210+
console.log('Test NodeRuntime.waitForDisconnect in worker');
211+
212+
const sessionWithoutWaiting = new Session();
213+
sessionWithoutWaiting.connect();
214+
const sessionWithoutWaitingPost = doPost.bind(null, sessionWithoutWaiting);
215+
216+
await sessionWithoutWaitingPost('NodeWorker.enable', {
217+
waitForDebuggerOnStart: true
218+
});
219+
await post('NodeWorker.enable', { waitForDebuggerOnStart: true });
220+
221+
const attached = [
222+
waitForWorkerAttach(session),
223+
waitForWorkerAttach(sessionWithoutWaiting)
224+
];
225+
226+
let worker = null;
227+
const exitPromise = runWorker(2, (w) => worker = w);
228+
229+
const [{ sessionId: sessionId1 }, { sessionId: sessionId2 }] =
230+
await Promise.all(attached);
231+
232+
const workerSession1 = new WorkerSession(session, sessionId1);
233+
const workerSession2 = new WorkerSession(sessionWithoutWaiting, sessionId2);
234+
235+
await workerSession2.post('Runtime.enable');
236+
await workerSession1.post('Runtime.enable');
237+
await workerSession1.post('NodeRuntime.notifyWhenWaitingForDisconnect', {
238+
enabled: true
239+
});
240+
await workerSession1.post('Runtime.runIfWaitingForDebugger');
241+
242+
worker.postMessage('resume');
243+
244+
await waitForEvent(workerSession1, 'NodeRuntime.waitingForDisconnect');
245+
post('NodeWorker.detach', { sessionId: sessionId1 });
246+
await waitForEvent(workerSession2, 'Runtime.executionContextDestroyed');
247+
248+
await exitPromise;
249+
250+
await post('NodeWorker.disable');
251+
await sessionWithoutWaitingPost('NodeWorker.disable');
252+
sessionWithoutWaiting.disconnect();
253+
}
254+
209255
async function test() {
210256
const session = new Session();
211257
session.connect();
@@ -219,6 +265,7 @@ async function test() {
219265

220266
await testNoWaitOnStart(session, post);
221267
await testTwoWorkers(session, post);
268+
await testWaitForDisconnectInWorker(session, post);
222269

223270
session.disconnect();
224271
console.log('Test done');

0 commit comments

Comments
 (0)