Skip to content

Keep detached daemon from holding the caller's stdio pipes. Closes #2080 - #2094

Open
waldekmastykarz wants to merge 2 commits into
dotnet:mainfrom
waldekmastykarz:fix-detach-blocks-output-capture
Open

waldekmastykarz wants to merge 2 commits into
dotnet:mainfrom
waldekmastykarz:fix-detach-blocks-output-capture

Conversation

@waldekmastykarz

Copy link
Copy Markdown
Collaborator

devproxy --detach hung callers that capture its output (devproxy --detach 2>&1 | Out-String, $(devproxy --detach), subprocess/execSync with pipes).

Cause

On Windows, Process.Start calls CreateProcess with bInheritHandles = TRUE, so the daemon inherits every inheritable handle of the devproxy --detach parent, not just the redirected pipes assigned as its stdio. The stdout/stderr handles the caller passes in are inheritable, so the long-running daemon kept the caller's pipe open and the caller never saw EOF.

On Unix, fork/exec replaces fds 0–2 with the redirected pipes, so the caller's pipe isn't held (verified on macOS: out=$(devproxy --detach ... | cat) returns in ~1s).

Changes

  • Before spawning the daemon, clear HANDLE_FLAG_INHERIT on the parent's std handles (StandardHandleInheritance, Windows-only, no-op elsewhere). The parent keeps using them; only inheritance is affected.
  • Redirect the daemon's stdin too (and close it right away), so the daemon holds none of the caller's stdio. The daemon doesn't read stdin (hotkeys are already disabled for --_internal-daemon).
  • Kept stdout/stderr redirected to pipes (rather than null) so early-startup failures are still reported by the parent.
  • Added Detach_WithCapturedOutput_ParentOutputReachesEofWhileDaemonKeepsRunning (text + json): runs devproxy --detach with captured pipes, requires EOF within 15s of the parent exiting, and checks the daemon is still running.

Testing

  • ProcessSmokeTests pass on macOS (11/11).
  • Not run on Windows locally (CI is Linux-only); the new test is the regression guard there.

Closes #2080

On Windows, Process.Start uses CreateProcess with bInheritHandles=TRUE, so
the daemon inherited the caller's inheritable stdout/stderr handles. Callers
that read devproxy --detach output to EOF (| Out-String, $(...), subprocess
pipes) then hung until the daemon exited. Clear the inherit flag on the
parent's std handles before spawning, redirect the daemon's stdin as well,
and add an integration test that captures --detach output and requires EOF.

Closes dotnet#2080

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@waldekmastykarz
waldekmastykarz requested a review from a team as a code owner November 5, 2026 10:44
Copilot AI balanced review requested due to automatic review settings November 5, 2026 10:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The EOF-timeout assertion can fail before the daemon PID is captured, causing cleanup to leave the detached daemon running after the failed test.

1 open issue
What changed in this PR

Fixes detached startup hanging callers that capture output by preventing the daemon from retaining the caller’s standard I/O handles.

Changes:

  • Disables inheritance of the launcher’s standard handles on Windows.
  • Redirects and closes daemon stdin while preserving stdout/stderr capture for startup errors.
  • Adds text and JSON regression tests requiring captured output to reach EOF while the daemon remains running.
File Description
DevProxy/​Proxy/​StandardHandleInheritance.cs Adds Windows-only standard-handle inheritance control.
DevProxy/​Program.cs Applies inheritance control and redirects daemon stdin.
DevProxy.Integration.Tests/​ProcessSmokeTests.cs Tests captured-output EOF and continued daemon operation.

Review effort: Balanced

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Reported checks cover only macOS tests and Linux builds, leaving Windows captured-output EOF—including merged stdout/stderr while the daemon remains alive—and early-startup error reporting unverified.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

This branch has not been deployed

No deployments
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.

devproxy --detach blocks callers that capture its output

2 participants