fix(wrap): detect stale proxy on target port and auto-cleanup before starting#1356
Open
lennney wants to merge 1 commit into
Open
fix(wrap): detect stale proxy on target port and auto-cleanup before starting#1356lennney wants to merge 1 commit into
lennney wants to merge 1 commit into
Conversation
Contributor
PR governanceThis PR follows the template and is marked ready for human review. |
1e8bafa to
72513ea
Compare
…starting Adds _ensure_port_free() and helpers to _start_proxy() that: - Detect if target port is already in use (via existing _port_bind_error) - Find the owning process via /proc/net/tcp (Linux) or lsof (macOS) - Only kills processes identified as stale headroom proxies - Reports clear error for non-headroom processes - Uses zero new dependencies Fixes the case where a terminal is killed, leaving an orphaned headroom proxy on the port — the next wrap would wait 30s then fail with a confusing RuntimeError. Now it auto-cleans and restarts. Tests: 11 new tests for all helpers + edge cases (50 total, all pass)
72513ea to
630ca1c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When a terminal running
headroom wrap <agent>is killed without proper cleanup (window close, SSH timeout, crash), the background proxy process becomes orphaned and continues holding the proxy port. The nextheadroom wrapon the same port waits 30-45 seconds (the proxy cold-start window) and then fails with a confusingRuntimeError("Proxy failed to start...").This PR adds stale proxy detection and auto-cleanup at the top of
_start_proxy(). Before spawning uvicorn, it checks whether the target port is already occupied by a headroom proxy (orphaned or otherwise). If so, it kills the old proxy and starts fresh. If the port is held by a non-headroom process, it reports a clear error.Type of Change
Changes Made
headroom/cli/wrap.py: Add_ensure_port_free(),_find_process_on_port(),_linux_find_process_on_port(),_resolve_inode_to_pid(),_is_headroom_proxy(),_kill_process(). New functions detect stale headroom proxy on the target port and clean it up before_start_proxy()spawns uvicorn. Uses only/proc/net/tcp+/proc/*/fd/(Linux) orlsof(macOS fallback). Zero new dependencies.tests/test_cli/test_wrap_helpers.py: Add 11 new tests covering all helper functions, /proc/net/tcp parsing, socket symlink matching, tcp6 fallback, stale detection, non-headroom rejection, and kill escalation.Testing
pytest):python -m pytest tests/test_cli/test_wrap_helpers.py::TestEnsurePortFree -v— 11 passedruff check .)mypy headroom)Test Output
Real Behavior Proof
headroom proxy --port 18794, verify bound via socket probe, call_ensure_port_free(18794)from the modified code, verify return value True, verify socket probe returns None (port free), verify old process dead viaos.kill(pid, 0)→ OSError_ensure_port_freedetected the stale proxy via/proc/net/tcp+/proc/PID resolution, sent SIGTERM, waited 3s, verified port free, returned True. Port 18794 was free and the old PID was confirmed dead. For non-headroom processes (e.g. HTTP server),_ensure_port_freereturned False with no kill./proc/net/tcpunavailable,lsofnot guaranteed — gracefully returns None). macOS withlsoffallback (code path exists but no macOS CI). Headroom proxy on macOS (no macOS runner available).Review Readiness
Checklist