57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""Mark a supervisor-ordered stop as planned so SIGTERM exits cleanly.
|
|
|
|
Runs as systemd ``ExecStop=`` before ``KillSignal=SIGTERM``. A raw
|
|
``systemctl restart/stop hermes-gateway`` bypasses the ``hermes gateway``
|
|
CLI, so no takeover (``--replace``) or planned-stop marker exists when the
|
|
SIGTERM lands; the gateway classifies it as an unexpected kill, exits
|
|
non-zero, and the journal records ``Failed with result exit-code`` even
|
|
though the restart was intentional.
|
|
|
|
The unit's ``Environment=HERMES_HOME=`` is inherited here, so the shared
|
|
:func:`gateway.status.write_planned_stop_marker` helper lands the marker in
|
|
the right profile home with PID + start-time identity. Best-effort and
|
|
never blocking: any failure returns 0 so the stop/restart proceeds.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
|
|
|
|
def _resolve_target_pid(argv: list[str] | tuple[str, ...]) -> int | None:
|
|
"""Explicit ``argv[1]``, else systemd's ``$MAINPID``. None when unknown.
|
|
|
|
No PID-file fallback on purpose: marking the recorded PID without proof
|
|
it is the process systemd is about to signal could mislabel an unrelated
|
|
shutdown as planned.
|
|
"""
|
|
raw: object = None
|
|
if len(argv) > 1 and argv[1]:
|
|
raw = argv[1]
|
|
else:
|
|
raw = os.environ.get("MAINPID")
|
|
try:
|
|
pid = int(str(raw).strip())
|
|
except (TypeError, ValueError, AttributeError):
|
|
return None
|
|
return pid if pid > 0 else None
|
|
|
|
|
|
def main(argv: list[str] | tuple[str, ...] | None = None) -> int:
|
|
"""Write the planned-stop marker for the supervised PID. Always 0."""
|
|
try:
|
|
pid = _resolve_target_pid(list(argv) if argv is not None else sys.argv)
|
|
if pid is None:
|
|
return 0
|
|
from gateway.status import write_planned_stop_marker
|
|
|
|
write_planned_stop_marker(pid)
|
|
except Exception:
|
|
pass
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|