From 5d626e247d8f47d4d21c0167a3ab1fd119837b2b Mon Sep 17 00:00:00 2001 From: Andrey Cheptsov Date: Sun, 11 Oct 2026 09:48:04 +0200 Subject: [PATCH] Run dstack server on the asyncio event loop uvloop spawns subprocesses with fork(). With gRPC and OpenTelemetry loaded, the forked ssh child could crash before exec and hang the server for up to 5 minutes (#4362). Co-Authored-By: Claude Opus 5.5 (1M context) --- src/dstack/_internal/cli/commands/server.py | 2 ++ src/tests/_internal/cli/commands/test_server.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/tests/_internal/cli/commands/test_server.py diff --git a/src/dstack/_internal/cli/commands/server.py b/src/dstack/_internal/cli/commands/server.py index 255f92e9a5..3769d9b77d 100644 --- a/src/dstack/_internal/cli/commands/server.py +++ b/src/dstack/_internal/cli/commands/server.py @@ -103,6 +103,8 @@ def _command(self, args: argparse.Namespace): reload_excludes=reload_excludes, log_level=uvicorn_log_level, workers=1, + # uvloop spawns subprocesses with fork(), which can hang the server (#4362). + loop="asyncio", ) def _configure_logging(self) -> None: diff --git a/src/tests/_internal/cli/commands/test_server.py b/src/tests/_internal/cli/commands/test_server.py new file mode 100644 index 0000000000..5b8b4d0e9c --- /dev/null +++ b/src/tests/_internal/cli/commands/test_server.py @@ -0,0 +1,12 @@ +import os +from unittest.mock import patch + +from dstack._internal.cli.commands import server +from tests._internal.cli.common import run_dstack_cli + + +class TestServerCommand: + def test_runs_uvicorn_on_asyncio_loop(self): + with patch.dict(os.environ), patch.object(server.uvicorn, "run") as uvicorn_run: + assert run_dstack_cli(["server"]) == 0 + assert uvicorn_run.call_args.kwargs["loop"] == "asyncio"