fix(heartbeat): replace bare except Exception with specific types and intent comments

This commit is contained in:
2026-04-30 20:19:52 -04:00
parent 72498f81b2
commit c648d8b04e

View File

@@ -19,7 +19,7 @@ from datetime import datetime, timezone
from typing import Any, Optional from typing import Any, Optional
from fastapi import APIRouter, Depends, HTTPException, Request from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel from pydantic import BaseModel, ValidationError
from decnet.config import DeckyConfig from decnet.config import DeckyConfig
from decnet.logging import get_logger from decnet.logging import get_logger
@@ -60,7 +60,8 @@ def _extract_peer_fingerprint(scope: dict[str, Any]) -> Optional[str]:
if chain: if chain:
peer_der = chain[0] peer_der = chain[0]
source = "primary" source = "primary"
except Exception: except (AttributeError, KeyError, TypeError):
# scope["extensions"]["tls"] structure varies across uvicorn versions
peer_der = None peer_der = None
if peer_der is None: if peer_der is None:
@@ -71,7 +72,8 @@ def _extract_peer_fingerprint(scope: dict[str, Any]) -> Optional[str]:
peer_der = ssl_obj.getpeercert(binary_form=True) peer_der = ssl_obj.getpeercert(binary_form=True)
if peer_der: if peer_der:
source = "fallback" source = "fallback"
except Exception: except (AttributeError, OSError):
# transport may not be an SSL transport, or the handshake may be incomplete
peer_der = None peer_der = None
if not peer_der: if not peer_der:
@@ -121,6 +123,7 @@ async def _reconcile_topology_report(
try: try:
topos = await repo.list_topologies(status=TopologyStatus.ACTIVE) topos = await repo.list_topologies(status=TopologyStatus.ACTIVE)
except Exception: except Exception:
# Non-fatal: reconcile is best-effort; the host stays alive regardless
log.exception("heartbeat: could not list active topologies") log.exception("heartbeat: could not list active topologies")
return return
mine = [t for t in topos if t.get("target_host_uuid") == host_uuid] mine = [t for t in topos if t.get("target_host_uuid") == host_uuid]
@@ -139,6 +142,7 @@ async def _reconcile_topology_report(
try: try:
hydrated = await hydrate(repo, tid) hydrated = await hydrate(repo, tid)
except Exception: except Exception:
# Non-fatal: skip this topology; mutator reconcile loop will retry
log.exception("heartbeat: hydrate failed tid=%s", tid) log.exception("heartbeat: hydrate failed tid=%s", tid)
continue continue
if hydrated is None: if hydrated is None:
@@ -155,6 +159,7 @@ async def _reconcile_topology_report(
tid, host_uuid, reported_id, reported_hash, expected, tid, host_uuid, reported_id, reported_hash, expected,
) )
except Exception: except Exception:
# Non-fatal: mutator reconcile loop will detect the mismatch again next heartbeat
log.exception("heartbeat: failed to flag resync tid=%s", tid) log.exception("heartbeat: failed to flag resync tid=%s", tid)
@@ -192,7 +197,7 @@ async def heartbeat(
for decky_dict in status_body.get("deckies") or []: for decky_dict in status_body.get("deckies") or []:
try: try:
d = DeckyConfig(**decky_dict) d = DeckyConfig(**decky_dict)
except Exception: except (ValidationError, TypeError):
log.exception("heartbeat: skipping malformed decky payload host=%s", req.host_uuid) log.exception("heartbeat: skipping malformed decky payload host=%s", req.host_uuid)
continue continue
rstate = runtime.get(d.name) or {} rstate = runtime.get(d.name) or {}