fix(gateway): runtime-status writer merges over out-of-process stamps

The background writer persisted the in-memory canonical snapshot verbatim. origin/main re-read gateway_state.json on every write, so keys stamped by other processes survived; with the snapshot they were clobbered on the next publish. Out-of-process writers exist: hermes gateway migrate --standalone (_reconcile_standalone_runtime) rewrites the live multiplexer's file, and container_boot seeds desired_state/migrated_from. Re-read the file in the writer thread immediately before writing and lay the gateway's fields over it: the gateway wins for every key it owns, foreign keys survive.
This commit is contained in:
kshitijk4poor
2026-09-20 17:12:34 +05:30
committed by kshitij
parent d27ee657b1
commit 489df88d6d

View File

@@ -135,7 +135,7 @@ class _RuntimeStatusWriter:
self._writing_generation = generation
error: Optional[BaseException] = None
try:
(self._write_fn or _write_json_file)(path, payload)
(self._write_fn or _write_json_file)(path, _merge_over_on_disk(path, payload))
except BaseException as exc:
error = exc
with self._condition:
@@ -162,6 +162,16 @@ class _RuntimeStatusWriter:
_runtime_status_state_lock = threading.RLock()
_runtime_status_state_path: Optional[Path] = None
_runtime_status_state: Optional[dict[str, Any]] = None
def _merge_over_on_disk(path: Path, payload: dict[str, Any]) -> dict[str, Any]:
"""Lay the canonical snapshot over whatever is on disk right before writing. Out-of-process
writers (``hermes gateway migrate --standalone`` clearing multiplex-owned status, container_boot
seeding ``desired_state``) stamp this file directly; the gateway's fields win, theirs survive."""
existing = _read_json_file(path)
return {**existing, **payload} if isinstance(existing, dict) else payload
_runtime_status_writer_lock = threading.Lock()
_runtime_status_writer: Optional[_RuntimeStatusWriter] = None