diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-25 18:59:20 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-25 18:59:20 +0200 |
| commit | 2657ffd62ece8b8461d55b398139503ec504c3c6 (patch) | |
| tree | 0de6e0fadcdd1e989212613239239ee9d3b1a570 /packages/meshbay-node/src/meshbay_node/daemon.py | |
| parent | 3f3c67a4aff7b800c271e88e2bc5e5294b010fb9 (diff) | |
| download | meshbay-2657ffd62ece8b8461d55b398139503ec504c3c6.tar.gz | |
fix(node,client): survive a transient hub state on login, and surface a failed node-key link
Two defensive gaps turned a routine reset-and-reonboard into "impossible de
démarrer le node":
1. daemon._login_with_retry retried a 401 (node key not linked yet) but `raise`d
on every other status, so a 429 — the daemon's own 5s retries hitting the
sign-in rate limit — or a 502/503 while the hub restarts during a deploy
killed the process, and systemd crash-looped it. Those statuses (429, 5xx)
are now retried with a back-off that respects Retry-After, so a freshly
reset node stays alive (the operator needs it up to read its key) instead of
dying. A genuine 4xx (400/422) still raises.
2. create-group's linkNodeKey swallowed every error as "already linked or same
key" — but PUT /me/node_key is idempotent and returns 200 on a re-link, so
there was no benign error to hide: the catch only ever hid a real failure
(a rejected session, a bad key), letting the wizard proceed against a node
that looked linked but was not, which then could not authenticate. The link
failure now surfaces (detectNode shows it).
test_login_retry_is_resilient.py holds the retry behaviour (429/5xx retried,
Retry-After honoured, 401 stays alive, 400 still raises); red before, green
after. common/node/hub suites green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/daemon.py | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py index 4800dac..dc5df81 100644 --- a/packages/meshbay-node/src/meshbay_node/daemon.py +++ b/packages/meshbay-node/src/meshbay_node/daemon.py @@ -983,6 +983,23 @@ class NodeDaemon(EnrichmentMixin): self._config.hub.username, self._config.hub.url, ) await asyncio.sleep(5) + elif e.response.status_code in (429, 500, 502, 503, 504): + # Transient: the hub is busy (429 — often this daemon's own + # retry storm against the sign-in rate limit), restarting + # (502/503) or erroring (500/504). None of these is a reason + # to exit: the daemon exiting here crash-loops under systemd + # and strands the operator, who needs it alive to read the + # node key (`meshbay-node status`, the desktop client) so + # they can link it. Back off — respecting Retry-After when + # the hub sends one — and try again, rather than dying. + self._state["status"] = "waiting_for_hub" + delay = 10 + ra = (e.response.headers or {}).get("Retry-After") + if ra and str(ra).isdigit(): + delay = min(max(delay, int(ra)), 300) + log.warning("Hub returned %s on login — retrying in %ds", + e.response.status_code, delay) + await asyncio.sleep(delay) else: raise except Exception as e: |