diff --git a/cli/service_cli.py b/cli/service_cli.py index 3538fcce..d1dfbe97 100644 --- a/cli/service_cli.py +++ b/cli/service_cli.py @@ -170,8 +170,13 @@ def _start_detached( stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=os.name != "nt", + # CREATE_NO_WINDOW, not DETACHED_PROCESS: DETACHED_PROCESS makes Windows + # allocate a brand-new console for the service, which the default + # terminal surfaces as a visible window on every `service start`. + # CREATE_NO_WINDOW still runs without any window and still outlives the + # launcher (the console is private to the child, never inherited). creationflags=( - subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP + subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP ) if os.name == "nt" else 0, diff --git a/tests/app_server/test_service.py b/tests/app_server/test_service.py index f700f469..b1a35ab6 100644 --- a/tests/app_server/test_service.py +++ b/tests/app_server/test_service.py @@ -213,7 +213,9 @@ def test_service_exits_cleanly_after_control_stop(tmp_path, log_to_file, detache cwd=Path(__file__).resolve().parents[2], start_new_session=detached and os.name != "nt", creationflags=( - subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP + # Mirror the launcher: CREATE_NO_WINDOW, so the detached leg does + # not pop a console window on Windows (DETACHED_PROCESS would). + subprocess.CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP if detached and os.name == "nt" else 0 ),