From 7bce0ffe19a8f7b8e516a31bd48ad5592fa9f770 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Sun, 7 Jun 2026 14:56:44 +0200 Subject: [PATCH] Debounce transient snapshot fetch errors Introduce a `consecutiveSnapshotErrors` counter with a threshold of 3 to debounce transient fetch failures. The last known snapshot is preserved and UI notifications are suppressed until the threshold is met, filtering out intermittent device glitches. The counter resets on success. --- pmoapp/webapp/src/composables/useRenderers.ts | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pmoapp/webapp/src/composables/useRenderers.ts b/pmoapp/webapp/src/composables/useRenderers.ts index d66177d4..2746ed83 100644 --- a/pmoapp/webapp/src/composables/useRenderers.ts +++ b/pmoapp/webapp/src/composables/useRenderers.ts @@ -27,6 +27,12 @@ const loadingIds = reactive(new Set()); const queueRefreshingIds = reactive(new Set()); const selectedRendererId = ref(null); +// Compteur d'erreurs consécutives par renderer — on ne notifie l'utilisateur +// qu'après SNAPSHOT_ERROR_THRESHOLD échecs d'affilée pour absorber les hoquets +// transitoires des devices (Arylic, etc.). +const consecutiveSnapshotErrors = new Map(); +const SNAPSHOT_ERROR_THRESHOLD = 3; + // Cache des renderers (summary) const renderersCache = ref>(new Map()); const RENDERERS_CACHE_MS = 2000; @@ -367,19 +373,25 @@ async function fetchRendererSnapshot( const snapshot = await api.getRendererFullSnapshot(rendererId); snapshots.set(rendererId, snapshot); lastSnapshotAt.set(rendererId, Date.now()); - + consecutiveSnapshotErrors.set(rendererId, 0); + } catch (err) { - console.error(`[useRenderers] Erreur snapshot ${rendererId}:`, err); - // En cas d'erreur, on supprime le snapshot pour permettre une nouvelle tentative - snapshots.delete(rendererId); - - // Notifier l'utilisateur - const name = renderersCache.value.get(rendererId)?.friendly_name ?? rendererId; - uiStore.notifyError(`Impossible de récupérer l'état de « ${name} »`); + const count = (consecutiveSnapshotErrors.get(rendererId) ?? 0) + 1; + consecutiveSnapshotErrors.set(rendererId, count); + console.error(`[useRenderers] Erreur snapshot ${rendererId} (${count}/${SNAPSHOT_ERROR_THRESHOLD}):`, err); + + // Garder le dernier snapshot connu plutôt que de le supprimer — l'UI reste + // affichable même si le device est momentanément muet. + + // Notifier seulement après N échecs consécutifs pour absorber les hoquets passagers + if (count >= SNAPSHOT_ERROR_THRESHOLD) { + const name = renderersCache.value.get(rendererId)?.friendly_name ?? rendererId; + uiStore.notifyError(`Impossible de récupérer l'état de « ${name} »`); + // Remettre à zéro pour ne pas spammer si le device reste instable + consecutiveSnapshotErrors.set(rendererId, 0); + } } finally { - // Toujours nettoyer le flag de chargement loadingIds.delete(rendererId); - } }