Problem
After laptop sleep/wake cycles, old thv processes sometimes remain running and continue holding their ports. When attempting to restart these servers, the new process fails with:
failed to listen: listen tcp 127.0.0.1:XXXXX: bind: address already in use
This happens even with #3417 (SO_REUSEADDR), because SO_REUSEADDR cannot override an actively running process, it only helps with sockets in TIME_WAIT state.
Observed behavior
- Laptop goes to sleep with Datadog/Glean MCP servers running
- Laptop wakes up
- Old
thv start <server> processes are still running (visible in ps aux | grep thv)
thv start <server> or thv restart <server> fails because the old process holds the port
- Manual
kill <pid> is required before the server can start
Environment
- macOS (Apple Silicon)
- Toolhive v0.7.x
- Remote MCP servers (Datadog, Glean) using OAuth
Possible solutions
- PID file tracking: Store PID on start, check/kill stale process on restart
- Better signal handling: Ensure processes terminate cleanly on SIGTERM/SIGHUP during sleep
- Port-based cleanup: Before binding, check if another
thv process holds the port and terminate it
- Enhanced
thv restart: Make restart explicitly kill the old process before starting new one
Workaround
Currently using a wrapper script that runs pkill -f "thv start <server>" before starting.
Related
Happy to submit a PR if you'd like me to implement one of these solutions.
Problem
After laptop sleep/wake cycles, old
thvprocesses sometimes remain running and continue holding their ports. When attempting to restart these servers, the new process fails with:This happens even with #3417 (SO_REUSEADDR), because
SO_REUSEADDRcannot override an actively running process, it only helps with sockets inTIME_WAITstate.Observed behavior
thv start <server>processes are still running (visible inps aux | grep thv)thv start <server>orthv restart <server>fails because the old process holds the portkill <pid>is required before the server can startEnvironment
Possible solutions
thvprocess holds the port and terminate itthv restart: Make restart explicitly kill the old process before starting new oneWorkaround
Currently using a wrapper script that runs
pkill -f "thv start <server>"before starting.Related
Happy to submit a PR if you'd like me to implement one of these solutions.