fix(gateway): launchd identity requires darwin, like control_socket
This commit is contained in:
@@ -4,6 +4,7 @@ import math
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections.abc import Callable, Mapping
|
||||
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
@@ -93,6 +94,8 @@ def launchd_service_label(environ: Mapping[str, str] | None = None) -> str | Non
|
||||
``exit timeout = 1`` for them — treating those as a budget would cap the
|
||||
drain to 0 for a gateway Ctrl+C'd in such a terminal.
|
||||
"""
|
||||
if sys.platform != "darwin":
|
||||
return None
|
||||
env = os.environ if environ is None else environ
|
||||
label = str(env.get("XPC_SERVICE_NAME", "") or "").strip()
|
||||
if not label.startswith("ai.hermes"):
|
||||
@@ -110,7 +113,7 @@ def read_launchd_exit_timeout_s(
|
||||
"""Live ``ExitTimeOut`` (seconds) launchd enforces for this gateway's job.
|
||||
|
||||
Returns ``None`` — meaning "no launchd budget applies" — when the process
|
||||
is not launchd-owned (no ``XPC_SERVICE_NAME``), ``launchctl`` is missing
|
||||
is not launchd-owned (non-darwin, or no ``ai.hermes`` ``XPC_SERVICE_NAME``), ``launchctl`` is missing
|
||||
or fails, or the print output carries no ``exit timeout`` line. Callers
|
||||
must treat ``None`` as fail-open: the configured drain stands unchanged.
|
||||
"""
|
||||
@@ -118,11 +121,7 @@ def read_launchd_exit_timeout_s(
|
||||
if not label:
|
||||
return None
|
||||
if uid is None:
|
||||
# launchd is macOS-only; Windows has no os.getuid, so resolve it via getattr.
|
||||
_getuid = getattr(os, "getuid", None)
|
||||
if _getuid is None:
|
||||
return None
|
||||
uid = _getuid()
|
||||
uid = os.getuid() # only reachable on darwin: launchd_service_label() is None elsewhere
|
||||
domain = "system" if uid == 0 else f"gui/{uid}"
|
||||
try:
|
||||
proc = run(
|
||||
|
||||
@@ -17,6 +17,7 @@ from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
import gateway.restart as restart_mod
|
||||
from gateway.restart import (
|
||||
LAUNCHD_STOP_CLEANUP_RESERVE_S,
|
||||
effective_stop_drain_timeout,
|
||||
@@ -28,14 +29,17 @@ from gateway.shutdown_watchdog import resolve_shutdown_watchdog_delay
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"label, expected",
|
||||
"platform, label, expected",
|
||||
[
|
||||
("ai.hermes.gateway", 60.0 - LAUNCHD_STOP_CLEANUP_RESERVE_S),
|
||||
("darwin", "ai.hermes.gateway", 60.0 - LAUNCHD_STOP_CLEANUP_RESERVE_S),
|
||||
# App-coalition label (IDE integrated terminal) is not our job: no budget, drain unchanged.
|
||||
("application.com.example.ide.123", 180.0),
|
||||
("darwin", "application.com.example.ide.123", 180.0),
|
||||
# launchd is darwin-only (same predicate as control_socket): a leaked label elsewhere is ignored.
|
||||
("linux", "ai.hermes.gateway", 180.0),
|
||||
],
|
||||
)
|
||||
def test_capped_drain_fits_inside_launchd_budget_minus_reserve(label, expected):
|
||||
def test_capped_drain_fits_inside_launchd_budget_minus_reserve(monkeypatch, platform, label, expected):
|
||||
monkeypatch.setattr(restart_mod.sys, "platform", platform)
|
||||
# The incident shape: configured 180s, launchd clamps to 60s.
|
||||
assert resolve_launchd_capped_drain(180.0, 60.0) == 60.0 - LAUNCHD_STOP_CLEANUP_RESERVE_S
|
||||
# Never extends a short drain; no launchd budget leaves the configured drain alone.
|
||||
|
||||
Reference in New Issue
Block a user