Purge des états : un bug de 2 ans corrigé + nettoyage automatique + page Tâches enrichie (PRs #2650, #2651, #2652)

En testant la nouvelle vue Activité de la 4.82, on est tombé sur quelque chose d’inattendu — et ça a donné trois PRs qui se complètent. Merci énorme à @Will_71 pour ses tests sur sa propre base ! :folded_hands:

Épisode 1 — le bug invisible depuis 2 ans (PR #2650)

En voulant purger les états d’un capteur bavard (décocher « Conserver l’historique »), la tâche répondait instantanément : 0 states to delete… alors que la vue Activité affichait des milliers d’états pour cette feature.

Verdict après archéologie git :

Question Réponse
Cassé depuis v4.45.0 (août 2024)
Cause La migration DuckDB (#2104) a déplacé les états, mais 2 requêtes SQLite ont été oubliées
Endroit 1 purgeStatesByFeatureId (le toggle « Conserver l’historique ») comptait et supprimait dans SQLite, désormais vide → no-op total
Endroit 2 Le garde-fou de device.destroy (« too much states ») comptait aussi SQLite → protection anti-blocage morte
Pourquoi invisible Rien n’affichait l’historique par feature… jusqu’à la vue Activité

La #2650 migre les deux vers DuckDB (même requête que celle que destroy utilisait déjà) et garde le nettoyage des restes SQLite pour les installations pas encore migrées.

Épisode 2 — combien d’états orphelins traînent chez vous ? (PR #2651)

Conséquence du bug : chaque device/feature supprimé depuis 2 ans a pu laisser ses états « orphelins » dans DuckDB — invisibles, mais scannés par chaque requête et occupant du disque.

Sur proposition de @pierre-gilles : une tâche automatique one-shot au démarrage (pattern de la migration DuckDB : Variable système posée uniquement en fin de run → si Gladys redémarre en plein milieu, elle repart seule au boot suivant — testé en vrai en coupant le container au milieu :scissors:).

Et « la plus lente possible » : pas de comptage préalable (qui tenait la connexion lecture 15-20 min sur ma base), parcours en tranches hebdomadaires avec une pause de 5× la durée de chaque tranche — la purge ne consomme jamais qu’une fraction des ressources et s’adapte toute seule à la machine.

Test terrain Base Orphelins trouvés Durée Impact ressenti
Moi (serveur partagé avec HA + 2ᵉ Gladys) 448 M d’états 20 :grinning_face_with_smiling_eyes: 1 h 49 (cache froid) / 29 min (chaud) Vue Activité : 125 ms pendant la purge (contre 44 s avec la 1ʳᵉ version non bridée)
@Will_71 (laptop Fedora) 228 M d’états 45 400 000 (~20 % de sa base !) ~29 min « Aucun ralentissement, peut-être +2 s sur l’Activité »

Les 45 M de Will confirment que ce nettoyage automatique était nécessaire pour tout le monde.


Avant/Après :

Encore un grand merci à @Will_71 pour les tests complets des 2 PR

Épisode 3 — la page Tâches qui aurait détecté le bug en un jour (PR #2652)

Si la page Tâches avait affiché « 0 état trouvé » face à une Activité pleine, le bug de purge n’aurait pas survécu 2 ans. C’est maintenant le cas — les tâches portent des données structurées (traduites côté front, donc dans toutes les langues) :

  • Cible : Détecteur de présence cuisine › Détection mouvement
  • Étapes en direct : En attente de la base de données… / Calcul du nombre d’états… / Suppression des états… / Suppression des agrégats… (deux purges simultanées affichent honnêtement l’une qui travaille et l’autre qui attend)
  • Comptages : États à supprimer : N DuckDB + N SQLite — N agrégats, puis États supprimés : … en compte-rendu persistant
  • Compteur live pour la purge d’orphelins, % par tranches, durée qui tique pour les tâches en cours

Conception validée par les échanges sur la #2528 : aucune modification du wrapper de jobs — les tâches restent lancées par le pattern événement existant, et chaque job attache lui-même ses données via un paramètre optionnel d’updateProgress.

Pour la review

@pierre-gilles les 3 PRs sont prêtes (tests + coverage 100 % sur les lignes modifiées, CI verte, validées en réel sur deux installations). Ordre de merge : #2650#2651#2652 (la dernière est empilée sur les deux autres, son diff rétrécira après leurs merges).

Quand même cool quand un développement met à jour un bug caché :grin: