fix(runtime): run user code on a Proactor loop on Windows in run and script mode - #10817
Open
BurakErdemci wants to merge 2 commits into
Open
BurakErdemci wants to merge 2 commits into
BurakErdemci wants to merge 2 commits into
Conversation
…script mode On Windows, marimo installs WindowsSelectorEventLoopPolicy process-wide (at import of the islands generator and at server start) because the edit-mode ConnectionDistributor needs loop.add_reader(). Selector loops cannot spawn subprocesses, so asyncio.create_subprocess_exec in a cell raised NotImplementedError. marimo-team#9194 fixed this for edit/IPC kernels, which are child processes; run-mode kernels run in a server thread and script mode runs in the caller's process, so both still inherited Selector. Add run_on_subprocess_capable_loop, which runs a coroutine on a locally created ProactorEventLoop on Windows without touching the global policy (other threads create loops concurrently), and use it for in-process run-mode kernels and for AppScriptRunner. Other platforms keep plain asyncio.run. Run mode uses QueueDistributor, which does not use add_reader, so the kernel loop does not need Selector. Fixes marimo-team#9182
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
All contributors have signed the CLA ✍️ ✅ |
Author
|
I have read the CLA Document and I hereby sign the CLA |
BurakErdemci
marked this pull request as ready for review
September 13, 2026 14:38
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.
This pull request was authored by a coding agent.
📝 Summary
Closes #9182
On Windows, a cell that awaits
asyncio.create_subprocess_execraisesNotImplementedErrorinmarimo runand in script mode (python notebook.py). #9194 fixed edit mode only.marimo sets
WindowsSelectorEventLoopPolicyfor the whole process in two places: whenmarimo._islands._island_generatoris imported, and ininitialize_asyncio()at server start. A Selector loop on Windows cannot create subprocesses. Edit and IPC kernels run in child processes, and_bootstrap_subprocessswitches them back to Proactor. A run-mode kernel runs in a thread inside the server, andAppScriptRunnerruns in the caller's process, so both call plainasyncio.runand get a Selector loop.This PR adds
run_on_subprocess_capable_looptomarimo/_utils/asyncio_utils.py. On Windows it runs the coroutine on aProactorEventLoopthat it creates itself, and it leaves the global policy alone because the server and other kernel threads create loops at the same time. It usesasyncio.run(..., loop_factory=...)on 3.12+,asyncio.Runneron 3.11, and a copy ofasyncio.run's shutdown steps on 3.10. On other platforms it callsasyncio.run.launch_kerneluses the helper for in-process kernels (run mode and app host). The edit and IPC branches keep their current code.AppScriptRunneruses it for async notebooks.initialize_asyncio.test_run_mode_on_windows_does_not_touch_event_loop_policystated that run mode needs Selector forConnectionDistributor.add_reader(). Run mode usesQueueDistributor(seeNotificationListenerExtension._create_distributor), andConnectionDistributor.startholds the onlyadd_readercall in the codebase. I replaced that test with one that checks run mode calls the helper and leaves the policy unchanged. If run mode should stay on Selector for a reason I missed, let me know.Before and after (Windows 11, Python 3.13, a notebook with one async cell that runs
python -c "print('ok')"):python notebook.pyNotImplementedErroron_WindowsSelectorEventLoopokonProactorEventLoopmarimo run notebook.pyNotImplementedErrorokTests
tests/_utils/test_asyncio_utils.py: return value, exception propagation, pending task cancellation, closed loop,RuntimeErrorinside a running loop, and a Windows test that spawns a subprocess under the Selector policy and checks the policy object stays the same.tests/_ast/test_app.py::TestApp::test_run_async_subprocess(Windows only) fails withNotImplementedErroronmainand passes with this change.TestLaunchKernelEventLoop: updated run-mode tests for Windows and other platforms.test_session_manager_file_renamefails on Windows onmaintoo, because of the error message text.Not covered: a synchronous cell that calls
asyncio.run(...)in script mode still gets a Selector loop from the policy that the islands import sets. Changing that import-time policy looks like it would affect islandsbuild(), so I left that decision to you.📋 Pre-Review Checklist
✅ Merge Checklist