diff --git a/src/inspector/node_protocol.pdl b/src/inspector/node_protocol.pdl index 36d528b937a038..608521b467d9e4 100644 --- a/src/inspector/node_protocol.pdl +++ b/src/inspector/node_protocol.pdl @@ -71,6 +71,11 @@ experimental domain NodeWorker # Detaches from all running workers and disables attaching to new workers as they are started. command disable + # Detached from the worker with given sessionId. + command detach + parameters + SessionID sessionId + # Issued when attached to a worker. event attachedToWorker parameters diff --git a/src/inspector/runtime_agent.cc b/src/inspector/runtime_agent.cc index f8fdbe42d41e03..4056140e703493 100644 --- a/src/inspector/runtime_agent.cc +++ b/src/inspector/runtime_agent.cc @@ -16,10 +16,6 @@ void RuntimeAgent::Wire(UberDispatcher* dispatcher) { } DispatchResponse RuntimeAgent::notifyWhenWaitingForDisconnect(bool enabled) { - if (!env_->owns_process_state()) { - return DispatchResponse::Error( - "NodeRuntime domain can only be used through main thread sessions"); - } notify_when_waiting_for_disconnect_ = enabled; return DispatchResponse::OK(); } diff --git a/src/inspector/worker_agent.cc b/src/inspector/worker_agent.cc index d343de8494a36f..81706572e646ea 100644 --- a/src/inspector/worker_agent.cc +++ b/src/inspector/worker_agent.cc @@ -115,6 +115,11 @@ DispatchResponse WorkerAgent::disable() { return DispatchResponse::OK(); } +DispatchResponse WorkerAgent::detach(const String& sessionId) { + workers_->Detached(sessionId); + return DispatchResponse::OK(); +} + void NodeWorkers::WorkerCreated(const std::string& title, const std::string& url, bool waiting, diff --git a/src/inspector/worker_agent.h b/src/inspector/worker_agent.h index 402c7194163967..1bd25189bf3026 100644 --- a/src/inspector/worker_agent.h +++ b/src/inspector/worker_agent.h @@ -25,6 +25,7 @@ class WorkerAgent : public NodeWorker::Backend { DispatchResponse enable(bool waitForDebuggerOnStart) override; DispatchResponse disable() override; + DispatchResponse detach(const String& sessionId) override; private: std::shared_ptr frontend_; diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index b44d27254d5b54..8a12c2dddf7493 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -472,8 +472,8 @@ class NodeInspectorClient : public V8InspectorClient { runMessageLoop(); } - void waitForIoShutdown() { - waiting_for_io_shutdown_ = true; + void waitForSessionsDisconnect() { + waiting_for_sessions_disconnect_ = true; runMessageLoop(); } @@ -548,6 +548,8 @@ class NodeInspectorClient : public V8InspectorClient { } contextDestroyed(env_->context()); } + if (waiting_for_sessions_disconnect_ && !is_main_) + waiting_for_sessions_disconnect_ = false; } void dispatchMessageFromFrontend(int session_id, const StringView& message) { @@ -678,8 +680,9 @@ class NodeInspectorClient : public V8InspectorClient { bool shouldRunMessageLoop() { if (waiting_for_frontend_) return true; - if (waiting_for_io_shutdown_ || waiting_for_resume_) + if (waiting_for_sessions_disconnect_ || waiting_for_resume_) { return hasConnectedSessions(); + } return false; } @@ -723,7 +726,7 @@ class NodeInspectorClient : public V8InspectorClient { int next_session_id_ = 1; bool waiting_for_resume_ = false; bool waiting_for_frontend_ = false; - bool waiting_for_io_shutdown_ = false; + bool waiting_for_sessions_disconnect_ = false; // Allows accessing Inspector from non-main threads std::unique_ptr interface_; std::shared_ptr worker_manager_; @@ -819,11 +822,14 @@ void Agent::WaitForDisconnect() { fprintf(stderr, "Waiting for the debugger to disconnect...\n"); fflush(stderr); } - if (!client_->notifyWaitingForDisconnect()) + if (!client_->notifyWaitingForDisconnect()) { client_->contextDestroyed(parent_env_->context()); + } else if (is_worker) { + client_->waitForSessionsDisconnect(); + } if (io_ != nullptr) { io_->StopAcceptingNewConnections(); - client_->waitForIoShutdown(); + client_->waitForSessionsDisconnect(); } } diff --git a/test/parallel/test-worker-debug.js b/test/parallel/test-worker-debug.js index 8726d2a031ee32..4906f623e85ef1 100644 --- a/test/parallel/test-worker-debug.js +++ b/test/parallel/test-worker-debug.js @@ -206,6 +206,52 @@ async function testTwoWorkers(session, post) { await Promise.all([worker1Exited, worker2Exited]); } +async function testWaitForDisconnectInWorker(session, post) { + console.log('Test NodeRuntime.waitForDisconnect in worker'); + + const sessionWithoutWaiting = new Session(); + sessionWithoutWaiting.connect(); + const sessionWithoutWaitingPost = doPost.bind(null, sessionWithoutWaiting); + + await sessionWithoutWaitingPost('NodeWorker.enable', { + waitForDebuggerOnStart: true + }); + await post('NodeWorker.enable', { waitForDebuggerOnStart: true }); + + const attached = [ + waitForWorkerAttach(session), + waitForWorkerAttach(sessionWithoutWaiting) + ]; + + let worker = null; + const exitPromise = runWorker(2, (w) => worker = w); + + const [{ sessionId: sessionId1 }, { sessionId: sessionId2 }] = + await Promise.all(attached); + + const workerSession1 = new WorkerSession(session, sessionId1); + const workerSession2 = new WorkerSession(sessionWithoutWaiting, sessionId2); + + await workerSession2.post('Runtime.enable'); + await workerSession1.post('Runtime.enable'); + await workerSession1.post('NodeRuntime.notifyWhenWaitingForDisconnect', { + enabled: true + }); + await workerSession1.post('Runtime.runIfWaitingForDebugger'); + + worker.postMessage('resume'); + + await waitForEvent(workerSession1, 'NodeRuntime.waitingForDisconnect'); + post('NodeWorker.detach', { sessionId: sessionId1 }); + await waitForEvent(workerSession2, 'Runtime.executionContextDestroyed'); + + await exitPromise; + + await post('NodeWorker.disable'); + await sessionWithoutWaitingPost('NodeWorker.disable'); + sessionWithoutWaiting.disconnect(); +} + async function test() { const session = new Session(); session.connect(); @@ -219,6 +265,7 @@ async function test() { await testNoWaitOnStart(session, post); await testTwoWorkers(session, post); + await testWaitForDisconnectInWorker(session, post); session.disconnect(); console.log('Test done');