fix: boucle de retry infinie — _retry_pending écrasé par l'envoi d'action

Bug : _schedule_retry stockait retry_count=N dans _retry_pending, mais
l'envoi de l'action (ligne 2173) écrasait avec retry_count=0. Résultat :
le retry_count retombait toujours à 0, la condition retry_count < 3 restait
vraie → boucle infinie de retries.

Corrections :
- Ne pas écraser _retry_pending si l'entrée existe déjà (set par _schedule_retry)
- Guard de sécurité : extraire retry_count depuis les suffixes _retry de l'action_id

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-03-31 11:57:11 +02:00
parent 18792fd7b4
commit e8a8a588c1

View File

@@ -2168,8 +2168,9 @@ async def get_next_action(session_id: str, machine_id: str = "default"):
# Else: queue a changé entre temps (race condition bénigne), on envoie quand même # Else: queue a changé entre temps (race condition bénigne), on envoie quand même
# Sauvegarder l'action envoyée pour le retry (si la vérification échoue) # Sauvegarder l'action envoyée pour le retry (si la vérification échoue)
# NE PAS écraser si _schedule_retry a déjà mis le bon retry_count
action_id_sent = action.get("action_id", "") action_id_sent = action.get("action_id", "")
if action_id_sent: if action_id_sent and action_id_sent not in _retry_pending:
_retry_pending[action_id_sent] = { _retry_pending[action_id_sent] = {
"action": dict(action), "action": dict(action),
"retry_count": 0, "retry_count": 0,
@@ -2228,6 +2229,18 @@ async def report_action_result(report: ReplayResultReport):
retry_count = retry_info["retry_count"] if retry_info else 0 retry_count = retry_info["retry_count"] if retry_info else 0
original_action = retry_info["action"] if retry_info else None original_action = retry_info["action"] if retry_info else None
# Guard de sécurité : détecter le retry_count depuis l'action_id si non trouvé
# Évite la boucle infinie si _retry_pending est désynchronisé
if retry_count == 0 and "_retry" in action_id:
import re
retry_suffixes = re.findall(r"_retry\d+", action_id)
retry_count = max(retry_count, len(retry_suffixes))
if retry_count > 0:
logger.warning(
f"retry_count corrigé par action_id : {retry_count} "
f"(action_id contient {len(retry_suffixes)} suffixes _retry)"
)
# Mettre à jour le dernier screenshot reçu # Mettre à jour le dernier screenshot reçu
screenshot_after = report.screenshot_after or report.screenshot screenshot_after = report.screenshot_after or report.screenshot
if screenshot_after: if screenshot_after: