René's URL Explorer Experiment


Title: Share one event loop per test module to stop Windows socketpair churn by maxisbey · Pull Request #3070 · modelcontextprotocol/python-sdk · GitHub

Open Graph Title: Share one event loop per test module to stop Windows socketpair churn by maxisbey · Pull Request #3070 · modelcontextprotocol/python-sdk

X Title: Share one event loop per test module to stop Windows socketpair churn by maxisbey · Pull Request #3070 · modelcontextprotocol/python-sdk

Description: Share one event loop per test module instead of creating a fresh one for every async test, to stop a Windows CI flake caused by event-loop churn. Motivation and Context test (3.12, locked, windows-latest) flaked with two failures that are really one event: test_client_tolerates_405_on_get_and_delete failed before its body ran with OSError: [WinError 10055] ("insufficient buffer space or queue full"), raised from asyncio.new_event_loop() while anyio's pytest plugin was creating the test's runner. On Windows every new event loop builds its self-pipe via socket.socketpair(), which CPython emulates as a real loopback TCP listen/connect/accept. The next test on the same worker was then blamed for the half-built loop's ResourceWarning: unclosed event loop (GC → unraisable → promoted to error by filterwarnings = ["error"]). The churn behind it: anyio's runner is lease-counted, so with only function-scoped async fixtures every async test creates and destroys its own event loop (anyio docs, agronholm/anyio#686). This suite has ~2,740 async tests and runs them in ~30s across 4 xdist workers on Windows CI — hundreds of loopback socketpair create/close cycles per second, each parking a connection in TIME_WAIT for ~120s. WinError 10055 is a transient kernel buffer failure under that churn; each loop creation is a lottery ticket and a Windows job currently buys ~2,740 of them (measured: exactly one socketpair() call per async test). The fix holds a module-scoped anyio runner lease (autouse fixture in tests/conftest.py), so each xdist worker reuses one loop per module. Measured on the flaked SHA with a socket.socketpair counter: 2,737 → ~380 socketpair calls per run on windows-latest, peak TIME_WAIT 4,164 → 400, with identical test outcomes on both windows-latest and ubuntu-latest. Six modules parametrize anyio_backend (trio + MockClock, SelectorEventLoop) and shadow the lease fixture with a sync no-op: a module-scoped lease can't depend on the function-scoped parameter (pytest fails with ScopeMismatch — loud, so a future module that forgets the shadow can't misbehave silently), the held runner wouldn't match the requested backend anyway, and tests/client/test_stdio.py's direct trio.run(...) calls collide with a lingering asyncio loop's wakeup fd on Windows. When these modules run, the previous module's runner has already been torn down, so their behavior is unchanged. Session scope would cut churn further (~10 socketpairs/run) but was rejected: it breaks all anyio_backend-parametrized tests with ScopeMismatch and the direct-trio tests on Windows via the wakeup-fd collision (both verified empirically). How Has This Been Tested? Full suite on windows-latest and ubuntu-latest at the flaked SHA with this patch: identical pass/skip counts to baseline, zero new failures, socketpair churn measured via an injected socket.socketpair counter and a TIME_WAIT sampler. Alternative scopes (session, package) were also run on both platforms to map exactly which tests conflict; the module + shadow shape is the one with zero behavior change. ./scripts/test locally: 100.00% coverage, strict-no-cover clean. Breaking Changes None — test infrastructure only. New convention for contributors: a test module that parametrizes anyio_backend must shadow _module_runner_lease (documented in the fixture's docstring in tests/conftest.py; forgetting it fails loudly at setup). Types of changes Bug fix (non-breaking change which fixes an issue) Checklist I have read the MCP Documentation My code follows the repository's style guidelines New and existing tests pass locally I have added appropriate error handling I have added or updated documentation as needed Additional context Tests in the same module now share loop-scoped state. An audit found no bare asyncio.create_task, set_event_loop, exception-handler, or executor usage anywhere in tests/ or src/mcp/, so nothing depends on per-test loop isolation today; a future test leaking a background task would surface as order-dependence within its own module. The residual ~380 loop creations (the six opt-out modules plus one loop per module per worker) keep a small tail of exposure. If the flake ever reappears, the next increment is moving the ~12 parametrized/direct-trio tests into small sibling modules so the two big opted-out files (test_jsonrpc_dispatcher.py, test_streamable_http_modern.py) rejoin the shared loop. AI Disclaimer

Open Graph Description: Share one event loop per test module instead of creating a fresh one for every async test, to stop a Windows CI flake caused by event-loop churn. Motivation and Context test (3.12, locked, windows-...

X Description: Share one event loop per test module instead of creating a fresh one for every async test, to stop a Windows CI flake caused by event-loop churn. Motivation and Context test (3.12, locked, windows-...

Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/pull/3070

X: @github

direct link

Domain: github.com

route-pattern/:user_id/:repository/pull/:id/files(.:format)
route-controllerpull_requests
route-actionfiles
fetch-noncev2:953d6299-faa4-7393-2ea5-4e1b80cc933e
current-catalog-service-hashae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b
request-idDAE2:BF910:4A0F19:6741D5:6A586BA2
html-safe-nonce69ba7782859a710abd09c2a447315b83087a13bb107737ab2c21fa933d7fb79c
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJEQUUyOkJGOTEwOjRBMEYxOTo2NzQxRDU6NkE1ODZCQTIiLCJ2aXNpdG9yX2lkIjoiNTg1MTE3NDM5NDU1NTU1ODgxOCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9
visitor-hmacbc0886f747997cf671a3724c12152e855fc286497c4ca10d08fb8351bf6d0bc4
hovercard-subject-tagpull_request:4001066330
github-keyboard-shortcutsrepository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///pull_requests/show/files
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/modelcontextprotocol/python-sdk/pull/3070/files
twitter:imagehttps://avatars.githubusercontent.com/u/224885523?s=400&v=4
twitter:cardsummary_large_image
og:imagehttps://avatars.githubusercontent.com/u/224885523?s=400&v=4
og:image:altShare one event loop per test module instead of creating a fresh one for every async test, to stop a Windows CI flake caused by event-loop churn. Motivation and Context test (3.12, locked, windows-...
og:site_nameGitHub
og:typeobject
hostnamegithub.com
expected-hostnamegithub.com
None5f2a0c7865178af3d91dd9f13b0cdfc3c73a2529c873d2780bb4c01271a57ec6
turbo-cache-controlno-preview
diff-viewunified
go-importgithub.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git
octolytics-dimension-user_id182288589
octolytics-dimension-user_loginmodelcontextprotocol
octolytics-dimension-repository_id862584018
octolytics-dimension-repository_nwomodelcontextprotocol/python-sdk
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id862584018
octolytics-dimension-repository_network_root_nwomodelcontextprotocol/python-sdk
turbo-body-classeslogged-out env-production page-responsive full-width
disable-turbotrue
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release8aae7b8d6caacacf5c66eaeb2702d8dc88d85b4a
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fmodelcontextprotocol%2Fpython-sdk%2Fpull%2F3070%2Ffiles
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub Copilot appDirect agents from issue to mergehttps://github.com/features/ai/github-app
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
View all resourceshttps://github.com/resources
GitHub SponsorsFund open source developershttps://github.com/open-source/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/open-source/accelerator
GitHub Starshttps://stars.github.com
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fmodelcontextprotocol%2Fpython-sdk%2Fpull%2F3070%2Ffiles
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fpull_requests%2Fshow%2Ffiles&source=header-repo&source_repo=modelcontextprotocol%2Fpython-sdk
Reloadhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Reloadhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Reloadhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Please reload this pagehttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
modelcontextprotocol https://github.com/modelcontextprotocol
python-sdkhttps://github.com/modelcontextprotocol/python-sdk
Notifications https://github.com/login?return_to=%2Fmodelcontextprotocol%2Fpython-sdk
Fork 3.6k https://github.com/login?return_to=%2Fmodelcontextprotocol%2Fpython-sdk
Star 23.6k https://github.com/login?return_to=%2Fmodelcontextprotocol%2Fpython-sdk
Code https://github.com/modelcontextprotocol/python-sdk
Issues 253 https://github.com/modelcontextprotocol/python-sdk/issues
Pull requests 292 https://github.com/modelcontextprotocol/python-sdk/pulls
Actions https://github.com/modelcontextprotocol/python-sdk/actions
Projects https://github.com/modelcontextprotocol/python-sdk/projects
Models https://github.com/modelcontextprotocol/python-sdk/models
Security and quality 6 https://github.com/modelcontextprotocol/python-sdk/security
Insights https://github.com/modelcontextprotocol/python-sdk/pulse
Code https://github.com/modelcontextprotocol/python-sdk
Issues https://github.com/modelcontextprotocol/python-sdk/issues
Pull requests https://github.com/modelcontextprotocol/python-sdk/pulls
Actions https://github.com/modelcontextprotocol/python-sdk/actions
Projects https://github.com/modelcontextprotocol/python-sdk/projects
Models https://github.com/modelcontextprotocol/python-sdk/models
Security and quality https://github.com/modelcontextprotocol/python-sdk/security
Insights https://github.com/modelcontextprotocol/python-sdk/pulse
Sign up for GitHub https://github.com/signup?return_to=%2Fmodelcontextprotocol%2Fpython-sdk%2Fissues%2Fnew%2Fchoose
terms of servicehttps://docs.github.com/terms
privacy statementhttps://docs.github.com/privacy
Sign inhttps://github.com/login?return_to=%2Fmodelcontextprotocol%2Fpython-sdk%2Fissues%2Fnew%2Fchoose
maxisbeyhttps://github.com/maxisbey
mainhttps://github.com/modelcontextprotocol/python-sdk/tree/main
windows-loop-churnhttps://github.com/modelcontextprotocol/python-sdk/tree/windows-loop-churn
Conversation 2 https://github.com/modelcontextprotocol/python-sdk/pull/3070
Commits 2 https://github.com/modelcontextprotocol/python-sdk/pull/3070/commits
Checks 34 https://github.com/modelcontextprotocol/python-sdk/pull/3070/checks
Files changed https://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Please reload this pagehttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Share one event loop per test module to stop Windows socketpair churn https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#top
Show all changes 2 commits https://github.com/modelcontextprotocol/python-sdk/pull/3070/files
f896bf5 Share one event loop per test module to stop Windows socketpair churn maxisbey Jul 2, 2026 https://github.com/modelcontextprotocol/python-sdk/pull/3070/commits/f896bf50a6320660a6a7b2c4ebaa602b5b0bf244
af18fe0 Drop the AGENTS.md note; the conftest fixture docstring covers the co… maxisbey Jul 7, 2026 https://github.com/modelcontextprotocol/python-sdk/pull/3070/commits/af18fe0ca2785cf42fdaa38d44637e76e48befc4
Clear filters https://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Please reload this pagehttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
Please reload this pagehttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
test_input_required.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-76ab06321b60046aadb54457281134c5864034437dacdb0b843710905992c538
test_stdio.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-49f66b09e4d89b29b440c955c429fe948dbcc3bbb08fffb504cf40be24382352
conftest.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-e52e4ddd58b7ef887ab03c04116e676f6280b824ab7469d5d3080e5cba4f2128
test_timeouts.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-72f06b25a7e212f804121ef810f403578c4acd67b76b86ccda04618012a9930d
test_streamable_http_modern.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-1e3c8aa3513b03c2ac6b7534d2b3a45dcbf59ef32f158028e9cc2fff0760893f
test_jsonrpc_dispatcher.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-ce6a750fbce4c4bfa60b1845cdd92c08be0c2ed1fdcecdcb2a2efa24170efabd
test_windows.py https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-314c849a12297cace60d12dc9f5983e06fac171fdb2a7ed454a389c4e08aebb1
tests/client/test_input_required.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-76ab06321b60046aadb54457281134c5864034437dacdb0b843710905992c538
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/client/test_input_required.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-76ab06321b60046aadb54457281134c5864034437dacdb0b843710905992c538
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-76ab06321b60046aadb54457281134c5864034437dacdb0b843710905992c538
tests/client/test_stdio.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-49f66b09e4d89b29b440c955c429fe948dbcc3bbb08fffb504cf40be24382352
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/client/test_stdio.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-49f66b09e4d89b29b440c955c429fe948dbcc3bbb08fffb504cf40be24382352
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-49f66b09e4d89b29b440c955c429fe948dbcc3bbb08fffb504cf40be24382352
tests/conftest.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-e52e4ddd58b7ef887ab03c04116e676f6280b824ab7469d5d3080e5cba4f2128
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/conftest.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-e52e4ddd58b7ef887ab03c04116e676f6280b824ab7469d5d3080e5cba4f2128
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-e52e4ddd58b7ef887ab03c04116e676f6280b824ab7469d5d3080e5cba4f2128
tests/interaction/lowlevel/test_timeouts.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-72f06b25a7e212f804121ef810f403578c4acd67b76b86ccda04618012a9930d
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/interaction/lowlevel/test_timeouts.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-72f06b25a7e212f804121ef810f403578c4acd67b76b86ccda04618012a9930d
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-72f06b25a7e212f804121ef810f403578c4acd67b76b86ccda04618012a9930d
tests/server/test_streamable_http_modern.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-1e3c8aa3513b03c2ac6b7534d2b3a45dcbf59ef32f158028e9cc2fff0760893f
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/server/test_streamable_http_modern.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-1e3c8aa3513b03c2ac6b7534d2b3a45dcbf59ef32f158028e9cc2fff0760893f
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-1e3c8aa3513b03c2ac6b7534d2b3a45dcbf59ef32f158028e9cc2fff0760893f
tests/shared/test_jsonrpc_dispatcher.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-ce6a750fbce4c4bfa60b1845cdd92c08be0c2ed1fdcecdcb2a2efa24170efabd
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/shared/test_jsonrpc_dispatcher.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-ce6a750fbce4c4bfa60b1845cdd92c08be0c2ed1fdcecdcb2a2efa24170efabd
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-ce6a750fbce4c4bfa60b1845cdd92c08be0c2ed1fdcecdcb2a2efa24170efabd
tests/transports/stdio/test_windows.pyhttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-314c849a12297cace60d12dc9f5983e06fac171fdb2a7ed454a389c4e08aebb1
View file https://github.com/modelcontextprotocol/python-sdk/blob/af18fe0ca2785cf42fdaa38d44637e76e48befc4/tests/transports/stdio/test_windows.py
Open in desktop https://desktop.github.com
https://github.co/hiddenchars
https://github.com/modelcontextprotocol/python-sdk/pull/3070/{{ revealButtonHref }}
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-314c849a12297cace60d12dc9f5983e06fac171fdb2a7ed454a389c4e08aebb1
https://github.com/modelcontextprotocol/python-sdk/pull/3070/files#diff-314c849a12297cace60d12dc9f5983e06fac171fdb2a7ed454a389c4e08aebb1
Please reload this pagehttps://github.com/modelcontextprotocol/python-sdk/pull/3070/files
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.