Repository navigation
fix(clients): stop hanging when the local server never accepts connections - #10611
leilei3167 wants to merge 1 commit into
Conversation
|
| def launch(): | ||
| with mock.patch.dict("sys.modules", {"sglang": mock.Mock()}): | ||
| LocalProvider.launch(lm, launch_kwargs={"timeout": 1}) |
There was a problem hiding this comment.
Hung workers leave mocks installed
When the six-second watchdog expires, _outcome_within returns without stopping its worker. That worker still holds the sys.modules patch open until LocalProvider.launch finishes. Even after the test fails, later tests can therefore import the fake sglang module and fail for unrelated reasons.
This is a non-blocking test-isolation concern. Keep the module patch in the main test's scope so it is restored on failure, or run the potentially hanging launch in a separate process that the watchdog can terminate and join.
Artifacts
Executed controlled-hang verification script
- The script invokes the original decorated test in non-hanging and hanging modes, checks module visibility, and releases the worker for cleanup; it reproduces the candidate without changing tracked code.
- Ran the original test with an immediate controlled readiness timeout; the worker stopped, the test passed, and no fake sglang module remained.
Hung launch leaves the module mock installed
- Blocked readiness past the shortened watchdog and imported sglang before releasing the worker; the import returned the mock after watchdog return and the mock persisted through test failure, confirming contamination.
📝 Changes Description
Fixes #10609.
LocalProvider.launchnever returned when the port refused connections.wait_for_servercheckedtimeoutonly after a non-200 response. A closed port makesrequests.getraiseRequestException, and that branch only slept, so the deadline never fired andprocess.kill()inlaunchwas never reached. A server process that exits during startup leaves the caller waiting the same way.wait_for_servernow checks the deadline on that error path, and raisesTimeoutErroras soon as the server process has exited.launchkills the process on any exception from the wait when it is still running.The new tests in
tests/clients/test_lm_local.pycover a closed port withtimeout=1, a process that has already exited, and a process that stays up but never accepts a connection. Before this change those calls were still running after 6 seconds. After the change,pytest tests/clients/test_lm_local.pyreports 6 passed, andruff check --fix-only --diffon the two files is clean.✅ Contributor Checklist
No GPU or SGLang install is required for the new tests. They stop after 6 seconds so a hang fails the test instead of stalling the job.