From 002c459981cb3a12aa284b2304bc87605f19552a Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 16 Mar 2026 05:03:11 -0700 Subject: [PATCH] fix(gateway): remove recursive ExecStop from systemd units, extend TimeoutStopSec to 60s * fix(gateway): avoid recursive ExecStop in user systemd unit * fix: extend ExecStop removal and TimeoutStopSec=60 to system unit The cherry-picked PR #1448 fix only covered the user systemd unit. The system unit had the same TimeoutStopSec=15 and could benefit from the same 60s timeout for clean shutdown. Also adds a regression test for the system unit. --------- Co-authored-by: Ninja --- hermes_cli/gateway.py | 8 ++------ tests/hermes_cli/test_gateway_service.py | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 10bf2c7c..2399436c 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -371,8 +371,6 @@ def get_hermes_cli_path() -> str: # ============================================================================= def generate_systemd_unit(system: bool = False, run_as_user: str | None = None) -> str: - import shutil - python_path = get_python_path() working_dir = str(PROJECT_ROOT) venv_dir = str(PROJECT_ROOT / "venv") @@ -381,7 +379,6 @@ def generate_systemd_unit(system: bool = False, run_as_user: str | None = None) # Build a PATH that includes the venv, node_modules, and standard system dirs sane_path = f"{venv_bin}:{node_bin}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - hermes_cli = shutil.which("hermes") or f"{python_path} -m hermes_cli.main" hermes_home = str(Path(os.getenv("HERMES_HOME", Path.home() / ".hermes")).resolve()) @@ -408,7 +405,7 @@ Restart=on-failure RestartSec=10 KillMode=mixed KillSignal=SIGTERM -TimeoutStopSec=15 +TimeoutStopSec=60 StandardOutput=journal StandardError=journal @@ -423,7 +420,6 @@ After=network.target [Service] Type=simple ExecStart={python_path} -m hermes_cli.main gateway run --replace -ExecStop={hermes_cli} gateway stop WorkingDirectory={working_dir} Environment="PATH={sane_path}" Environment="VIRTUAL_ENV={venv_dir}" @@ -432,7 +428,7 @@ Restart=on-failure RestartSec=10 KillMode=mixed KillSignal=SIGTERM -TimeoutStopSec=15 +TimeoutStopSec=60 StandardOutput=journal StandardError=journal diff --git a/tests/hermes_cli/test_gateway_service.py b/tests/hermes_cli/test_gateway_service.py index 708d0ee8..ffd38178 100644 --- a/tests/hermes_cli/test_gateway_service.py +++ b/tests/hermes_cli/test_gateway_service.py @@ -53,6 +53,23 @@ class TestSystemdServiceRefresh: ] +class TestGeneratedSystemdUnits: + def test_user_unit_avoids_recursive_execstop_and_uses_extended_stop_timeout(self): + unit = gateway_cli.generate_systemd_unit(system=False) + + assert "ExecStart=" in unit + assert "ExecStop=" not in unit + assert "TimeoutStopSec=60" in unit + + def test_system_unit_avoids_recursive_execstop_and_uses_extended_stop_timeout(self): + unit = gateway_cli.generate_systemd_unit(system=True) + + assert "ExecStart=" in unit + assert "ExecStop=" not in unit + assert "TimeoutStopSec=60" in unit + assert "WantedBy=multi-user.target" in unit + + class TestGatewayStopCleanup: def test_stop_sweeps_manual_gateway_processes_after_service_stop(self, tmp_path, monkeypatch): unit_path = tmp_path / "hermes-gateway.service"