fix(gateway): keep pending /update completion notifications until the target platform reconnects

This commit is contained in:
Frowtek
2026-06-04 06:56:28 -07:00
committed by Teknium
parent a6a0a5b1b0
commit b7169f9bbb
3 changed files with 113 additions and 16 deletions
+26 -3
View File
@@ -15142,10 +15142,15 @@ class GatewayRunner:
if not adapter or not chat_id:
logger.warning("Update watcher: cannot resolve adapter/chat_id, falling back to completion-only")
# Fall back to old behavior: wait for exit code and send final notification
# Fall back to completion-only: wait for the exit code and send the
# final notification. _send_update_notification re-resolves the
# adapter on every call, so when the target platform is still
# reconnecting it returns False and keeps the markers. Keep polling
# until it actually delivers (returns True) instead of giving up
# after the first completion check — otherwise a platform that
# reconnects a few seconds after completion never gets notified.
while (pending_path.exists() or claimed_path.exists()) and loop.time() < deadline:
if exit_code_path.exists():
await self._send_update_notification()
if exit_code_path.exists() and await self._send_update_notification():
return
await asyncio.sleep(poll_interval)
if (pending_path.exists() or claimed_path.exists()) and not exit_code_path.exists():
@@ -15359,6 +15364,24 @@ class GatewayRunner:
platform = Platform(platform_str)
adapter = self.adapters.get(platform)
if not adapter and chat_id:
# The update finished, but the target platform has not
# reconnected yet (common right after the restart that
# `hermes update` triggers). Treating "adapter missing" as a
# definitive skip would delete the markers and silently lose the
# completion notification — the user never learns whether the
# update succeeded or timed out. Preserve the markers instead so
# a later retry (the watcher poll loop, or the next gateway
# startup) can deliver the result once the adapter is back.
logger.info(
"Update notification deferred: %s adapter not connected yet",
platform_str,
)
cleanup = False
active_pending_path = pending_path
claimed_path.replace(pending_path)
return False
if adapter and chat_id:
metadata = self._thread_metadata_for_target(
platform,