Skip to content

Fix Windows backend runtime isolation - #10

Open
flujo-app wants to merge 2 commits into
Kiln-AI:mainfrom
flujo-app:codex/windows-backend-runtime-fixes
Open

Fix Windows backend runtime isolation#10
flujo-app wants to merge 2 commits into
Kiln-AI:mainfrom
flujo-app:codex/windows-backend-runtime-fixes

Conversation

@flujo-app

Copy link
Copy Markdown

Summary

  • prevent incidental Modal imports from replacing the Windows asyncio policy used by Docker subprocesses
  • initialize backend-specific runtime state only after a backend is selected
  • stabilize Wasmtime architecture detection and Docker/HTTP lifecycle tests under parallel Windows runs
  • add regression coverage for Modal policy isolation and Windows runtime behavior

Dependency

Depends on #9. This branch starts from #9's MCP 1.x compatibility commit because the implementation and full suite were verified with that constraint. Please merge #9 first; once it lands, GitHub will automatically remove the shared dependency commit from this PR's diff.

Test plan

  • uv run python -m pytest -q -n auto . — 344 passed, 88 skipped
  • uvx ruff format --check on all changed files — passed
  • uvx ty check on changed production files — passed
  • git diff --check — passed

@flujo-app

Copy link
Copy Markdown
Author

Investigation summary

What happened

On Windows, the MCP end-to-end test reached the Docker backend but failed when Kilntainers tried to start the Docker subprocess. The surfaced MCP error was empty because FastMCP wrapped the underlying exception; the actual exception was NotImplementedError from asyncio.create_subprocess_exec().

Why it happened

CLI parser construction discovers every backend. That discovery imported the Modal SDK even when Docker was the selected backend. Modal 1.3.2 changes the process-wide Windows asyncio policy to WindowsSelectorEventLoopPolicy during import. Selector event loops on Windows do not support asyncio subprocess creation, so the unrelated Modal import prevented the Docker backend from launching docker.

Parallel execution also exposed several independent sources of test instability: Windows architecture detection could intermittently receive incomplete WMI data, lifecycle tests relied on fixed timing delays, the HTTP lifecycle test used a wrapper process and a fixed port, and cleanup could affect containers created by another worker.

What we changed

  • Added a backend prepare_runtime() hook and invoke it only after the CLI knows which backend was selected.
  • Made Modal SDK loading lazy. Incidental backend discovery now preserves the existing asyncio policy; selecting Modal explicitly allows Modal to configure the policy it needs.
  • Added regression tests covering both incidental Modal discovery and explicit Modal startup.
  • Added a reliable Windows architecture fallback for Wasmtime when platform/WMI data is incomplete.
  • Hardened lifecycle tests with readiness polling, event-based synchronization, dynamic ports, Windows process-group shutdown, per-test Docker labels, bounded cleanup, and less brittle timeouts.
  • Added Windows SIGBREAK handling so the HTTP lifecycle test can exercise graceful shutdown without terminating an unrelated wrapper process.

How we tested it

The original Docker MCP E2E path now passes. We also ran the complete suite in parallel on Windows with Docker available:

uv run python -m pytest -q -n auto . -rs
344 passed, 88 skipped

We additionally ran formatting checks on every changed file, type checking on the changed production files, and git diff --check; all passed.

What we did not test

  • Live Modal operations were skipped because Modal credentials were not configured. The import and event-loop-policy behavior is covered by local regression tests, but remote Modal execution is not.
  • E2B integration tests were skipped because E2B_API_KEY was not set.
  • Podman integration tests were skipped because the Podman CLI was not installed.
  • Linux and macOS were not exercised during this local validation.
  • MCP 2.x was not tested and is intentionally outside this PR's compatibility target; this PR depends on Fix startup failure with MCP 2.0 #9, which constrains MCP to the supported 1.x line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants