mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(update): pending fleet restart leaves gateways already on the checkout code alone
The catch-up restart stopped every gateway before re-checking whether any was actually on
pre-update code, so the gateway the same `hermes update` had just cold-started was killed
and (on Windows) the stop/start pair printed "No gateway was running" followed by a second
spawn. _run_pending_fleet_restart now skips when the fleet probe shows every live gateway
current on the checkout SHA (identity known; any stale/down/unknown row still restarts).
The Windows direct-spawn report no longer prints the PID twice ("(PID n) (PID: n)").
Part of #117051
This commit is contained in:
1 parent
eaef5ec717
commit
d6b0d37ece
3 files changed
+50
-2
No files matched your search
@@ -806,7 +806,7 @@ def _start_or_report_running(running_pids: list[int] | None = None) -> None:
|
||||
_report_already_running(running_pids)
|
||||
else:
|
||||
pid = _spawn_detached()
|
||||
_report_gateway_start(f"direct spawn (PID {pid})")
|
||||
_report_gateway_start("direct spawn")
|
||||
|
||||
|
||||
def _install_startup_fallback(script_path: Path, start_now: bool, detail: str) -> None:
|
||||
@@ -1610,7 +1610,7 @@ def start() -> None:
|
||||
# Manual starts use the same console-less direct spawn as restart() and install --start-now;
|
||||
# Scheduled Task / Startup entries are only login persistence.
|
||||
pid = _spawn_detached()
|
||||
_report_gateway_start(f"direct spawn (PID {pid})")
|
||||
_report_gateway_start("direct spawn")
|
||||
|
||||
|
||||
def _drain_gateway_pid(pid: int, drain_timeout: float) -> bool:
|
||||
|
||||
@@ -446,6 +446,23 @@ def _restart_systemd_gateway_units_best_effort(failed: list, listings) -> None:
|
||||
failed.extend(f"systemd-{scope} (listing unavailable)" for scope, _ in _SYSTEMD_SCOPES if scope not in answered)
|
||||
|
||||
|
||||
def _live_fleet_all_current() -> bool:
|
||||
"""True when the fleet probe finds at least one gateway and every row is ``current`` at the
|
||||
checkout SHA (identity known). Any unknown/stale/down row or a failed probe -> False (restart)."""
|
||||
checkout_sha = _current_checkout_sha()
|
||||
if not checkout_sha:
|
||||
return False
|
||||
try:
|
||||
from hermes_cli.update_receipt import collect_fleet_versions
|
||||
fleet = collect_fleet_versions()
|
||||
except Exception as exc:
|
||||
logger.debug("Pending fleet restart: fleet probe failed: %s", exc)
|
||||
return False
|
||||
if not fleet or _fleet_covered_gateways(fleet) is None:
|
||||
return False
|
||||
return all(row.get("state") == "current" and str(row.get("code_sha")) == checkout_sha for row in fleet)
|
||||
|
||||
|
||||
def _run_pending_fleet_restart() -> bool:
|
||||
"""Catch-up restart for gateways left on pre-update code. Never raises.
|
||||
|
||||
@@ -474,6 +491,14 @@ def _run_pending_fleet_restart() -> bool:
|
||||
logger.debug("Pending fleet restart: gateway probe failed: %s", exc)
|
||||
pids = None
|
||||
|
||||
# A gateway this very update cold-started (or a manual `hermes gateway restart` seconds
|
||||
# ago) already serves the checkout code; stopping it here re-kills the fleet, and on
|
||||
# Windows the stop/start pair then reports "No gateway was running" plus a second spawn
|
||||
# (#117051). Skip when EVERY live gateway is current on the checkout SHA.
|
||||
if pids and _live_fleet_all_current():
|
||||
print(" ✓ Every running gateway already serves the checkout code — nothing to restart.")
|
||||
return True
|
||||
|
||||
failed: list = []
|
||||
try:
|
||||
# Snapshot before stopping: Restart=no units can disappear from list-units on a clean exit.
|
||||
|
||||
@@ -362,6 +362,29 @@ def test_run_pending_restart_true_when_no_gateways(monkeypatch, capsys):
|
||||
assert "Pending fleet restart completed" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_run_pending_restart_skips_gateways_already_on_checkout_code(monkeypatch, capsys):
|
||||
"""A gateway the update itself cold-started seconds earlier is already current on the checkout
|
||||
SHA: the catch-up must not stop it (the Windows stop/start pair then printed "No gateway was
|
||||
running" plus a second spawn, #117051) and must report nothing to restart."""
|
||||
sha = "c" * 40
|
||||
monkeypatch.setattr(update_cmd_fleet, "_current_checkout_sha", lambda: sha)
|
||||
monkeypatch.setattr("hermes_cli.gateway.find_gateway_pids", lambda **k: [48096])
|
||||
monkeypatch.setattr(
|
||||
"hermes_cli.update_receipt.collect_fleet_versions",
|
||||
lambda: [{"profile": "default", "pid": 48096, "code_sha": sha, "state": "current"}],
|
||||
)
|
||||
stopped = []
|
||||
monkeypatch.setattr("hermes_cli.gateway.kill_gateway_processes", lambda **k: stopped.append(k))
|
||||
monkeypatch.setattr("hermes_cli.gateway_windows.restart", lambda: stopped.append("windows-restart"))
|
||||
monkeypatch.setattr("hermes_cli.gateway_windows.is_installed", lambda: True)
|
||||
monkeypatch.setattr(update_cmd_fleet, "_restart_macos_launchd_gateways", lambda *a, **k: None)
|
||||
monkeypatch.setattr(update_cmd_fleet, "_systemd_gateway_unit_listings", lambda: [])
|
||||
|
||||
assert update_cmd._run_pending_fleet_restart() is True
|
||||
assert stopped == []
|
||||
assert "nothing to restart" in capsys.readouterr().out
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_update integration (mocked git / restart)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in new issue
Block a user