Skip to content

fix(proxy): spawn debug adapters detached on POSIX only; on win32 the missing console made every Delve launch 8-13 s slow (#889) - #931

Merged
debugmcpdev merged 2 commits into
mainfrom
fix/889-adapter-spawn-win32
Oct 12, 2026
Merged

debugmcpdev merged 2 commits into
mainfrom
fix/889-adapter-spawn-win32

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Closes #889.

What the measurement found

The issue blamed Delve's cold go build inside the 30 s proxy-init deadline. The build is a minority of the time. Reproduced on this Windows 11 box, idle:

How dlv dap was started listening after launch → response
spawn(...) plain, windowsHide: true 0.12 s 1.16 s
spawn(...) with detached: true (the adapter manager, before this PR) 3.0–5.5 s 8.0–9.4 s

Delve's own log under the detached spawn (--log --log-output=dap,debugger): the go build that takes 0.2 s warm in a shell took 6 s, and launching process → Adding target (starting the debuggee) took 4 s. Isolating the Windows creation flags with Python's creationflags on dlv version: DETACHED_PROCESS (what Node's detached sets, no inherited console) and CREATE_NEW_CONSOLE take 2–3 s each; CREATE_NO_WINDOW (what windowsHide sets) and CREATE_NEW_PROCESS_GROUP take 0.1 s like a plain spawn. go version, node, python, java, ruby and CodeLLDB start in the same time detached or not — only Delve pays, and it pays once per process it creates.

So a debug-mode launch of a trivial program was 8–13 s idle on the main path (measured through the dev backend too: 5 s to accept the connection, 10 s to answer launch), and under pre-push load it crossed the two fixed 30 s limits that launch sits under: the proxy's initialization deadline (DEFAULT_PROXY_INITIALIZATION_TIMEOUT_MS) and the worker's MinimalDapClient request timeout. The four sightings' proxy logs all have the same shape: launch sent, Delve's Building … output event 2 ms later, then silence until the kill.

The cold build itself: 3–9 s with a throwaway GOCACHE, 0.2 s warm. A beforeAll warm build (the issue's proposal 1) was written, measured, and dropped: it saved ~2 s and left the 5–10 s stall in place.

The fix

GenericAdapterManager.spawn passes detached: this.platform !== 'win32'. On POSIX detached puts the adapter in its own process group, which shutdown()'s group kill relies on (#337); on win32 the tree-kill is taskkill /T and never used the group, and windowsHide keeps the adapter window-less (CREATE_NO_WINDOW). Two unit tests pin the per-platform flag.

Measured after

  • tests/adapters/go/integration/go-exit-code.test.ts alone: 48 s → 15 s; the two debug-mode cases 15–20 s → 5.7 s each; the proxy log's launch → response 1.17 s (debug) / 0.23 s (noDebug).
  • Dev backend on the new build: Python (stopOnEntry, continue, exit 0), JavaScript (exit_code_test.js, exit 7), Go (exit_code, exit 3) all paused at entry and ran to completion; no dlv.exe, debugpy or js-debug process left after close_debug_session.
  • e2e on Windows, --project e2e: javascript-attach (10), cpp-attach (2), go (7), python (5) — 24/24; then dotnet (3), java (7), ruby (6), rust (4), dart (8) — 28/28; cobol (28) — 28/28. Every adapter's spawn changed on Windows, and every adapter's smoke ran.

Verification

  • npm run typecheck:all, npm run lint, pnpm run changelog:check
  • tests/unit/proxy, tests/proxy, session-manager-operations-coverage (1163 tests)
  • Go integration suite on the built dist/
  • e2e smokes on Windows: javascript-attach, cpp-attach, go, python (24/24)
  • e2e smokes on Windows: dotnet, java, ruby, rust, dart (28/28)
  • e2e smoke on Windows: cobol (28/28)

🤖 Generated with Claude Code

https://claude.ai/code/session_01PKWRJTTqYdYrhDn2z9Et5P

cynarlab and others added 2 commits October 12, 2026 17:22
… missing console made every Delve launch 8-13 s slow (#889)

Node's `detached` is DETACHED_PROCESS on Windows: the adapter gets no
console. Delve pays for that at every process it creates. Measured on
Windows 11, idle: `dlv version` takes 0.1 s with an inherited or hidden
console (CREATE_NO_WINDOW, which windowsHide sets) and 2-3 s under
DETACHED_PROCESS or CREATE_NEW_CONSOLE, isolated per creation flag; go,
node, python, java, ruby and CodeLLDB start in the same time either way.
Under a detached `dlv dap`, Delve's own log shows the warm `go build`
taking 6 s (0.2 s in a shell) and the debuggee start 4 s, so a 1.16 s
launch took 8-13 s on the main path and crossed the two fixed 30 s
launch limits under pre-push load, which is the #889 flake: all four
sightings' proxy logs show `launch`, Delve's `Building ...` output event
2 ms later, then silence until the kill. The cold build the issue blamed
is 3-9 s with a throwaway GOCACHE; a beforeAll warm build was measured
and dropped (it saved ~2 s and left the stall).

The POSIX process group is what shutdown() signals (-pid, issue #337), so
detached stays there; the win32 tree-kill is taskkill /T and never used a
group. Two unit tests pin the per-platform flag.

After: the Go integration suite alone 48 s -> 15 s, each debug-mode case
5.7 s, launch -> response 1.17 s.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKWRJTTqYdYrhDn2z9Et5P
…d now say unref'd, detached off win32 (#889)

Five comments taught the pre-#889 mechanism: the python adapter's
pythonw rationale (the launcher got a visible console because the
adapter had none; it now inherits the adapter's hidden one), the reaper,
janitor and js adapter notes about "detached+unref'd" vsDebugServer
instances (the stranding comes from Windows having no parent-death
signal, not from detached), the worker launcher's "detached adapter
children", and the adapter manager's own spawn log comment. The spawn
comment also names the condition CREATE_NO_WINDOW depends on: no stdio
slot may be 'inherit'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PKWRJTTqYdYrhDn2z9Et5P
@codecov

codecov Bot commented Oct 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@debugmcpdev
debugmcpdev merged commit d5c1ab6 into main Oct 12, 2026
14 checks passed
@debugmcpdev
debugmcpdev deleted the fix/889-adapter-spawn-win32 branch October 12, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flake: go-exit-code.test.ts first launch hits the 30 s proxy-init deadline while Delve builds the fixture under load (pre-push, Windows)

2 participants