Repository navigation
TEST: Release Windows event-loop wakeup ports on close - #3361
Queued
Richard Lundeen (richlundeen) wants to merge 2 commits into
Queued
Richard Lundeen (richlundeen) wants to merge 2 commits into
Richard Lundeen (richlundeen) wants to merge 2 commits into
Conversation
Keep function-scoped Proactor loops while avoiding TCP TIME_WAIT buildup from private wakeup sockets. Cover port release, cleanup failures, cancellation, thread wakeups, and subprocess support. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3cf835d-626c-4bae-94c2-09317acbf654
Roman Lutz (romanlutz)
approved these changes
Oct 20, 2026
Use a single pytest-asyncio factory fixture for coroutine and fixture-only runners, require plugin 1.4, and check actual runner wiring. Bound thread wakeups and subprocess lifecycle checks, and verify child cleanup on deterministic timeout and cancellation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: a3cf835d-626c-4bae-94c2-09317acbf654
This branch has not been deployed
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
The Windows Python 3.13 unit-test job removed #3206 from the merge queue. Job 118347021912 reported
WinError 10055while setting uptests/unit/backend/test_runtime_lifecycle.py::test_saved_opt_in_is_required. The test body did not run. The stack was pytest-asyncio runner creation -> native Proactor event loop -> private TCP socket pair ->connect(). The other 29,821 tests passed.Windows implements the loop's private wakeup socket pair with TCP. Normal loop closure leaves connections in
TIME_WAIT; thousands of function-scoped loops can put pressure on the ephemeral port pool. A bounded local Windows experiment left 28 TCP entries after 32 native loop closures, but zero after abortive closure of only the two private wakeup sockets. The new 64-loop regression fails against the originalasyncio.new_event_loopfactory and passes with this fix.Use one pytest-asyncio factory fixture on Windows to keep native, function-scoped Proactor loops and release only their private wakeup sockets on close. Application sockets keep their normal close behavior. The native close path still runs if socket-option setup fails, and the error still propagates. Cancellation, thread wakeups, subprocess support, and refusal to close a running loop remain covered. Other platforms keep their existing loop setup.
The review update addresses both of Roman's findings: require pytest-asyncio 1.4 or later and apply the factory to synchronous tests with async fixtures as well as coroutine tests. The public 1.4 hook misses fixture-only runners, so the suite overrides the internal
_asyncio_loop_factoryfixture instead. Explicit wiring checks cover both paths and expose incompatible plugin changes. The lockfile changes only the minimum-version metadata; locked package versions and registry URLs are unchanged.Thread wakeup and cleanup waits are bounded. An independent thread-based watchdog also stops a stalled loop. The subprocess checks kill and reap an unfinished child in
finally, with deterministic timeout and cancellation coverage.This changes test infrastructure only. It does not change production code, share loops, add retries, or alter dataset refresh behavior. Test watchdogs use the existing shared deadlock backstop, not short latency assertions.
A later failure in the same merge group was the seeded Operations 390px E2E test. Open PR #3356 adds startup and preference synchronization to that same test flow; this PR does not duplicate its frontend changes.
Tests and Documentation
Windows, Python 3.14.2, pytest-asyncio 1.4.0:
uv sync --frozen --extra all- passed.uv run --no-sync pytest tests\unit\test_event_loop.py tests\unit\prompt_target\test_text_target.py tests\unit\backend\test_runtime_lifecycle.py -q -W error::pytest.PytestUnraisableExceptionWarning- passed: 86 tests.uv run --no-sync ty check test_support\event_loop.py tests\unit\conftest.py tests\unit\test_event_loop.py- passed.$env:UV_NO_SYNC='1'; make unit-test- passed: 29,690 tests, 50 skipped, in 16 minutes 3 seconds.$env:UV_NO_SYNC='1'; uv run --no-sync pre-commit run --all-files- passed: all hooks.uv lock --check --default-index https://pypi.org/simple- passed against the lockfile's existing registry.UV_DEFAULT_INDEXwas not changed.Session-only negative controls confirmed that substituting the original factory fails both runner-wiring assertions. A separate pytest process with thread-safe wakeups disabled exited through the independent watchdog after a controlled two-second limit rather than hanging. These diagnostic injections are not part of the committed suite.
Updated the unit-test contributor guide with factory coverage and the private plugin-fixture contract. No notebooks changed; JupyText and live-provider tests were not run.