Claude: refresh OAuth proactif + erreurs fatales distinctes (fini les reconnexions manuelles)
Le refresh token est rotatif : la chaîne se régénère seule indéfiniment tant que le nouveau token est persisté. La reconnexion manuelle n'était requise que lorsque cet invariant cassait. Trois correctifs : - Refresh PROACTIF : on rafraîchit dès qu'il reste < 2h sur le token (~8h de vie) au lieu des 2 dernières minutes. Un échec transitoire a des heures de marge avant que l'access token meure ; la fenêtre où un kill/timeout perd le token rotatif fraîchement rotaté passe de ~8h à quelques ms. Réglable via MONITORINK_CLAUDE_REFRESH_LEAD_MIN (défaut 120). - Distinction FATAL vs TRANSITOIRE : 400 invalid_grant / 401 sur l'endpoint token -> _RefreshFatal, sans backoff ni re-soumission en boucle (évite la reuse-detection qui révoque toute la famille). 429/5xx/réseau gardent le backoff exponentiel. - Visibilité + auto-réparation : le cas fatal affiche "Reconnexion Claude requise" (pas de repli cache silencieux) et l'alerte se referme seule dès qu'un token frais réapparaît sur disque (re-login isolé), sans redémarrer le conteneur. Timeout du POST de refresh porté à 45s (réglable, MONITORINK_CLAUDE_REFRESH_TIMEOUT) pour réduire la fenêtre de perte du token après rotation serveur. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,18 @@ class Config:
|
||||
ccusage_enabled: bool = field(
|
||||
default_factory=lambda: _get("MONITORINK_CCUSAGE", "0") in ("1", "true", "yes")
|
||||
)
|
||||
# Marge proactive de refresh OAuth : on rafraîchit dès qu'il reste MOINS que ça sur le token
|
||||
# (~8 h de vie), au lieu d'attendre les toutes dernières minutes. 2 h par défaut -> refresh
|
||||
# ~6 h avant l'échéance, ce qui laisse des heures de marge pour retenter un échec transitoire
|
||||
# (429/réseau) AVANT que l'access token meure, et fait tourner le refresh token rotatif tôt.
|
||||
claude_refresh_lead_minutes: int = field(
|
||||
default_factory=lambda: int(_get("MONITORINK_CLAUDE_REFRESH_LEAD_MIN", "120"))
|
||||
)
|
||||
# Timeout du POST de refresh. Généreux : réduit la fenêtre où le serveur a rotaté le refresh
|
||||
# token sans qu'on ait pu le persister (cause n°1 des reconnexions manuelles). Secondes.
|
||||
claude_refresh_timeout: int = field(
|
||||
default_factory=lambda: int(_get("MONITORINK_CLAUDE_REFRESH_TIMEOUT", "45"))
|
||||
)
|
||||
|
||||
# --- Météo (Open-Meteo, sans clé) ---
|
||||
weather_lat: float = field(default_factory=lambda: float(_get("MONITORINK_LAT", "48.8566")))
|
||||
@@ -127,6 +139,11 @@ class Config:
|
||||
default_factory=lambda: int(_get("MONITORINK_FULL_INTERVAL_MIN", "120"))
|
||||
)
|
||||
|
||||
@property
|
||||
def claude_refresh_lead_ms(self) -> int:
|
||||
"""Marge proactive de refresh en millisecondes (cf. claude_refresh_lead_minutes)."""
|
||||
return self.claude_refresh_lead_minutes * 60_000
|
||||
|
||||
@property
|
||||
def ha_entities(self) -> list[HAEntity]:
|
||||
return [HAEntity.parse(s) for s in _get_list("MONITORINK_HA_ENTITIES")]
|
||||
|
||||
Reference in New Issue
Block a user