[edge-infer W8] Omni serve CLI: uvloop optional, selector-loop asyncio.run on Windows

uvloop ships no Windows wheels, so 'import uvloop' at module scope in
entrypoints/cli/serve.py killed vllm-omni serve on Windows at import
(measured in the serving e2e after the fcntl fix). _run_forever() uses
uvloop where present and asyncio.run on WindowsSelectorEventLoopPolicy
otherwise, which zmq.asyncio needs. The remaining serve-import blocker
on the Windows venv was a missing dependency, torchaudio (vLLM's own
requirement), installed into the venvs rather than patched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
tzhouamandClaude Fable 5.1 committed 2026-09-18 19:09:22 +08:00
1 parent 502dd7bed0
commit 97d97b6503
1 file changed
+26 -2
+26 -2
View File
@@ -16,7 +16,10 @@ import signal
from types import FrameType
from typing import Any, cast
import uvloop
try:
import uvloop
except ImportError: # [edge-infer W8] uvloop has no Windows wheel; see _run_forever.
uvloop = None # type: ignore[assignment]
from vllm.entrypoints.cli.types import CLISubcommand
from vllm.entrypoints.launchers.cli_args import make_arg_parser, validate_parsed_serve_args
from vllm.entrypoints.serve.utils.api_utils import VLLM_SUBCMD_PARSER_EPILOG
@@ -102,6 +105,27 @@ def _ensure_vllm_platform():
)
def _run_forever(coro):
"""``uvloop.run`` where uvloop exists; ``asyncio.run`` on a selector loop elsewhere.
[edge-infer W8] uvloop ships no Windows wheels, so ``import uvloop`` at module
scope killed ``vllm-omni serve`` on Windows at import (the same defect vLLM's
own ``vllm/v1/utils.py`` needed a lazy binding for). On Windows the fallback
also has to be the selector loop: zmq.asyncio cannot run on the default
Proactor loop (see ``vllm_omni.edge.local.cli``).
"""
if uvloop is not None:
return uvloop.run(coro)
import asyncio
import sys
if sys.platform == "win32":
policy = getattr(asyncio, "WindowsSelectorEventLoopPolicy", None)
if policy is not None and not isinstance(asyncio.get_event_loop_policy(), policy):
asyncio.set_event_loop_policy(policy())
return asyncio.run(coro)
class OmniServeCommand(CLISubcommand):
"""The `serve` subcommand for the vLLM CLI."""
@@ -132,7 +156,7 @@ class OmniServeCommand(CLISubcommand):
if args.headless:
run_headless(args)
else:
uvloop.run(omni_run_server(args))
_run_forever(omni_run_server(args))
def validate(self, args: argparse.Namespace) -> None:
if args.stage_id is not None and (args.omni_master_address is None or args.omni_master_port is None):