Skip to content

Restore system proxy after a crashed instance#4

Closed
waldekmastykarz wants to merge 1 commit into
mainfrom
waldekmastykarz-restore-system-proxy-after-crash
Closed

Restore system proxy after a crashed instance#4
waldekmastykarz wants to merge 1 commit into
mainfrom
waldekmastykarz-restore-system-proxy-after-crash

Conversation

@waldekmastykarz

Copy link
Copy Markdown
Owner

Summary

When a detached Dev Proxy instance running with --as-system-proxy true is terminated uncleanly (crash, kill -9, OOM, power loss), the OS proxy is left pointing at the now-dead port and devproxy stop --force could not recover it — it printed Dev Proxy is not running. and exited 1, leaving the machine without working network access.

Root cause: StateManager prunes any state file whose PID is no longer alive before the stop command reads it, so a crashed instance's record is already gone by the time stop --force runs ⇒ no instance is found ⇒ SystemProxyManager.Disable() is never invoked. --force therefore only worked for a hung-but-alive instance, not the dead one it's meant to recover.

The fix decouples "restore the OS proxy" from "find a live instance."

Fixes dotnet#1731.

Changes

  • SystemProxyManager.cs (new) — cross-platform, idempotent Disable() (Windows WinINET via ProxyServer.DisableAllSystemProxies(), macOS toggle-proxy.sh off, Linux no-op) plus ReconcileOrphanedSystemProxiesAsync(). Reconciliation is guarded: the global OS proxy is only disabled when no live instance still owns it — otherwise only the stale record is removed.
  • StateManager.cs — added GetOrphanedSystemProxyStatesAsync() which reads records for dead PIDs with asSystemProxy: true without pruning them first, and extracted a non-pruning ReadStateFromFileAsync helper.
  • StopCommand.csdevproxy stop and devproxy stop --pid now reconcile crashed system-proxy orphans (restore the OS proxy + clean up the record) in addition to stopping live instances. Gated on Dev Proxy's own asSystemProxy record, so a proxy Dev Proxy didn't set is never touched.
  • Program.cs / ProxyEngine.cs — startup self-heal so a stale registration is recovered on the next run. The reconciliation runs at the very top of the detached launcher (before its state-loading port-conflict check, which would otherwise prune the orphan without restoring the proxy) and in ProxyEngine for foreground runs.

Safety

  • Disabling the system proxy is idempotent and cross-platform, so restoring it is low-risk.
  • Reconciliation only ever acts on a stale state record that Dev Proxy itself wrote with asSystemProxy: true — it never disables a corporate/third-party proxy.
  • The global OS proxy is only disabled when no live instance currently owns it.

Testing (macOS)

Verified with the built binary (system proxy was off, so Disable() was a safe no-op):

  • Crashed system-proxy orphan → stop restores it, deletes the record, exit 0
  • Nothing running → Dev Proxy is not running., exit 1
  • Non-system-proxy dead orphan → not treated as a restore
  • stop --pid on a crashed orphan → restored
  • Live instance + orphan present → graceful stop and orphan reconcile both succeed
  • Detached startup self-heal → Recovered system proxy left by a crashed Dev Proxy instance logged, orphan cleaned up

Full solution builds clean (0 warnings, 0 errors).

Notes

When a detached instance running as system proxy is terminated uncleanly,
the OS proxy was left pointing at a dead port and 'devproxy stop --force'
could not recover it: StateManager prunes state files for dead PIDs before
the stop command reads them, so no instance was found and the system proxy
was never disabled.

Reconcile orphaned system-proxy registrations independently of finding a
live instance:
- Add StateManager.GetOrphanedSystemProxyStatesAsync (reads records for dead
  PIDs with asSystemProxy=true without pruning them first).
- Add cross-platform, idempotent SystemProxyManager.Disable (Windows WinINET
  via ProxyServer.DisableAllSystemProxies, macOS toggle-proxy.sh off) and
  ReconcileOrphanedSystemProxiesAsync, guarded so the OS proxy is only
  disabled when no live instance still owns it.
- devproxy stop / stop --pid now restore the system proxy for crashed
  instances; self-heal also runs at startup (detached launcher and
  ProxyEngine) so a stale registration doesn't linger across runs.

Refs dotnet#1731. PID-reuse hardening tracked in dotnet#1755.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0b22cd4a-15a3-4a8c-8248-fe776339aa45
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 stop --force cannot restore the system proxy after a crashed instance

1 participant