From 0f239f49c6d6c38447ec51698701ff06197771de Mon Sep 17 00:00:00 2001 From: embwl0x Date: Tue, 14 Jul 2026 18:09:16 -0500 Subject: [PATCH] fix(gateway): stop systemd retries on fatal config --- hermes_cli/gateway.py | 3 +++ tests/hermes_cli/test_gateway_service.py | 3 +++ .../test_systemd_optional_directives.py | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 7b9817eadd8f..f45a0e85fb43 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -32,6 +32,7 @@ PROJECT_ROOT = Path(__file__).parent.parent.resolve() from gateway.status import terminate_pid from gateway.restart import ( DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUT, + GATEWAY_FATAL_CONFIG_EXIT_CODE, GATEWAY_SERVICE_RESTART_EXIT_CODE, parse_restart_drain_timeout, ) @@ -2761,6 +2762,7 @@ Environment="HERMES_HOME={hermes_home}" Restart=always RestartSec=5 RestartForceExitStatus={GATEWAY_SERVICE_RESTART_EXIT_CODE} +RestartPreventExitStatus={GATEWAY_FATAL_CONFIG_EXIT_CODE} KillMode=mixed KillSignal=SIGTERM ExecReload=/bin/kill -USR1 $MAINPID @@ -2795,6 +2797,7 @@ Environment="HERMES_HOME={hermes_home}" Restart=always RestartSec=5 RestartForceExitStatus={GATEWAY_SERVICE_RESTART_EXIT_CODE} +RestartPreventExitStatus={GATEWAY_FATAL_CONFIG_EXIT_CODE} KillMode=mixed KillSignal=SIGTERM ExecReload=/bin/kill -USR1 $MAINPID diff --git a/tests/hermes_cli/test_gateway_service.py b/tests/hermes_cli/test_gateway_service.py index ef563c34b49a..6dd6a2152314 100644 --- a/tests/hermes_cli/test_gateway_service.py +++ b/tests/hermes_cli/test_gateway_service.py @@ -14,6 +14,7 @@ import hermes_cli.gateway as gateway_cli from gateway import status from gateway.restart import ( DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUT, + GATEWAY_FATAL_CONFIG_EXIT_CODE, GATEWAY_SERVICE_RESTART_EXIT_CODE, ) @@ -435,6 +436,7 @@ class TestGeneratedSystemdUnits: assert "ExecStop=" not in unit assert "ExecReload=/bin/kill -USR1 $MAINPID" in unit assert f"RestartForceExitStatus={GATEWAY_SERVICE_RESTART_EXIT_CODE}" in unit + assert f"RestartPreventExitStatus={GATEWAY_FATAL_CONFIG_EXIT_CODE}" in unit # TimeoutStopSec must exceed the default drain_timeout (60s) so # systemd doesn't SIGKILL the cgroup before post-interrupt cleanup # (tool subprocess kill, adapter disconnect) runs — issue #8202. @@ -546,6 +548,7 @@ class TestGeneratedSystemdUnits: assert "ExecStop=" not in unit assert "ExecReload=/bin/kill -USR1 $MAINPID" in unit assert f"RestartForceExitStatus={GATEWAY_SERVICE_RESTART_EXIT_CODE}" in unit + assert f"RestartPreventExitStatus={GATEWAY_FATAL_CONFIG_EXIT_CODE}" in unit # TimeoutStopSec must exceed the default drain_timeout (60s) so # systemd doesn't SIGKILL the cgroup before post-interrupt cleanup # (tool subprocess kill, adapter disconnect) runs — issue #8202. diff --git a/tests/hermes_cli/test_systemd_optional_directives.py b/tests/hermes_cli/test_systemd_optional_directives.py index 34aa1793281c..cbefa4f2e4c6 100644 --- a/tests/hermes_cli/test_systemd_optional_directives.py +++ b/tests/hermes_cli/test_systemd_optional_directives.py @@ -139,6 +139,29 @@ WantedBy=default.target class TestSystemdUnitIsCurrent: + def test_unit_without_fatal_config_restart_policy_is_not_current( + self, tmp_path, monkeypatch, + ): + from hermes_cli import gateway as gw + + expected = """[Service] +Restart=always +RestartForceExitStatus=75 +RestartPreventExitStatus=78 +""" + installed = expected.replace("RestartPreventExitStatus=78\n", "") + unit_file = tmp_path / "hermes-gateway.service" + unit_file.write_text(installed) + + monkeypatch.setattr(gw, "get_systemd_unit_path", lambda system=False: unit_file) + monkeypatch.setattr( + gw, + "generate_systemd_unit", + lambda system=False, run_as_user=None: expected, + ) + + assert gw.systemd_unit_is_current(system=False) is False + def test_unit_without_optional_directives_is_current(self, tmp_path, monkeypatch): """Installed unit missing RestartMaxDelaySec/RestartSteps should be considered current when the generated unit includes them."""