Stati bereinigen: 2 Jahre alter Bug behoben + automatische Reinigung + Aufgaben-Seite erweitert (PRs #2650, #2651, #2652)

Beim Testen der neuen Aktivitätsansicht in der Version 4.82 stießen wir auf etwas Unerwartetes — und das führte zu drei sich ergänzenden PRs. Ein riesiges Dankeschön an @Will_71 für die Tests an seiner eigenen Datenbank! :folded_hands:

Episode 1 — der seit 2 Jahren unsichtbare Bug (PR #2650)

Beim Versuch, die Zustände eines redseligen Sensors zu löschen (Option „Verlauf speichern“ deaktiviert), antwortete die Aufgabe sofort: 0 states to delete… obwohl die Aktivitätsansicht tausende Zustände für dieses Feature anzeigte.

Urteil nach einer git-Archäologie:

Frage Antwort
Seit wann kaputt v4.45.0 (August 2024)
Ursache Die Migration zu DuckDB (#2104) hat die Zustände verschoben, aber 2 SQLite-Abfragen wurden vergessen
Ort 1 purgeStatesByFeatureId (der Schalter „Verlauf speichern“) zählte und löschte in SQLite, das nun leer ist → komplette No-Op
Ort 2 Der Schutzmechanismus von device.destroy („zu viele Zustände“) zählte ebenfalls in SQLite → tote Schutzfunktion gegen Blockierung
Warum unsichtbar Nichts zeigte den Verlauf pro Feature an… bis zur Aktivitätsansicht

Die #2650 migriert die beiden zu DuckDB (dieselbe Abfrage, die destroy bereits verwendete) und behält die Bereinigung der SQLite-Reste für noch nicht migrierte Installationen bei.

Episode 2 — wie viele Waisen-Zustände haben Sie zu Hause? (PR #2651)

Folge des Bugs: Jedes Device/Feature, das in den letzten 2 Jahren gelöscht wurde, konnte seine „Waisen“-Zustände in DuckDB zurücklassen — unsichtbar, aber von jeder Abfrage gescannt und Speicherplatz belegend.

Auf Vorschlag von @pierre-gilles: eine automatische Einmal-Aufgabe beim Starten (Migrationsmuster von DuckDB: Systemvariable wird nur am Ende des Runs gesetzt → wenn Gladys mitten im Prozess neu startet, startet sie beim nächsten Boot automatisch — getestet, indem der Container mitten im Prozess abgeschaltet wurde :scissors:).

Und „so langsam wie möglich“: Keine vorherige Zählung (die 15-20 Minuten die Leseverbindung blockierte auf meiner Datenbank), Durchlauf in wöchentlichen Abschnitten mit einer Pause von 5× der Dauer jedes Abschnitts — die Bereinigung verbraucht nie mehr als einen Bruchteil der Ressourcen und passt sich selbst an die Maschine an.

Feldtest Datenbank Gefundene Waisen Dauer Wahrgenommene Auswirkungen
Ich (geteilter Server mit HA + 2. Gladys) 448 M Zustände 20 :grinning_face_with_smiling_eyes: 1 h 49 (kalter Cache) / 29 min (warm) Aktivitätsansicht: 125 ms während der Bereinigung (gegenüber 44 s mit der ersten, ungebremsten Version)
@Will_71 (Fedora-Laptop) 228 M Zustände 45.400.000 (~20 % seiner Datenbank!) ~29 min „Keine Verlangsamung, vielleicht +2 s bei der Aktivität“

Die 45 M von Will bestätigen, dass diese automatische Bereinigung für alle notwendig war.


Vorher/Nachher :

Noch einmal ein großes Dankeschön an @Will_71 für die vollständigen Tests der 2 PRs

Episode 3 — die Aufgaben-Seite, die den Bug in einem Tag entdeckt hätte (PR #2652)

Wenn die Aufgaben-Seite „0 Zustände gefunden“ gegenüber einer vollen Aktivität angezeigt hätte, wäre der Lösch-Bug nicht 2 Jahre überlebt. Das ist jetzt der Fall — die Aufgaben haben strukturierte Daten (übersetzt auf der Frontend-Seite, also in allen Sprachen):

  • Ziel: Bewegungsmelder Küche › Bewegungserkennung
  • Live-Schritte: Warten auf die Datenbank… / Zählen der Anzahl der Zustände… / Löschen der Zustände… / Löschen der Aggregationen… (zwei gleichzeitige Löschvorgänge zeigen ehrlich an, welche arbeitet und welche wartet)
  • Zählungen: Zu löschende Zustände: N DuckDB + N SQLite — N Aggregationen, dann Gelöschte Zustände: … im dauerhaften Bericht
  • Live-Zähler für die Bereinigung von Waisen, % pro Abschnitten, tickende Dauer für laufende Aufgaben

Das Design wurde durch die Diskussionen in der #2528 validiert: keine Änderung des Job-Wrappers — die Aufgaben werden weiterhin durch das bestehende Ereignismuster gestartet, und jeder Job hängt seine Daten über einen optionalen Parameter von updateProgress an.

Für die Überprüfung

@pierre-gilles die 3 PRs sind bereit (Tests + 100 % Abdeckung auf den geänderten Zeilen, grüne CI, validiert in der Praxis auf zwei Installationen). Merge-Reihenfolge: #2650 → #2651 → #2652 (die letzte ist auf die beiden anderen gestapelt, ihr Diff wird nach deren Merges schmaler).

Doch ganz schön cool, wenn eine Entwicklung ein verstecktes Bug fix einpflegt :grin:

Trop cool @Terdious danke für die Entwicklungen und danke @Will_71 für die Tests !! :smiley:

Ich werde mir das ansehen!

@Terdious Könntest du Fable 5 auf die Kommentare von CodeRabbit starten?

Da gibt es wirklich kritische Punkte :smiley:

Erledigt!

CodeRabbit hatte recht mit dem kritischen Punkt: Der letzte unbeschränkte Abschnitt bewertete die während der Löschung geschriebenen Zustände gegen eine statische Momentaufnahme der Features — ein gepaartes Gerät während der ~30 Minuten Löschung konnte seine ersten Zustände verlieren. Behoben mit einem Cutoff, der vor der Momentaufnahme erfasst wurde, angewendet auf alle Abschnitte, + Regressions-Test. Der fehlende Test des „Null-Feature“-Zweigs wurde ebenfalls hinzugefügt; die SQL-Injection-Warnung ist ein falscher Positivfall (nur Platzhalter), darauf in der PR geantwortet.

Teilweise mein Fehler, geteilt mit Fable 5 in diesem Fall: Zwei für sich genommen vernünftige Entscheidungen (letzter offener Abschnitt, um während des Laufs geschriebene Zustände abzudecken + Feature-Snapshot zu Beginn) wurden in Kombination gefährlich — und ich hatte keine dedizierte Review-Runde am Ende der Entwicklung mit Fable eingeleitet. Gutes Beispiel dafür, dass die Cross-Review von Bot + Agent + Mensch unterschiedliche blinde Flecken aufdeckt :grinning_face_with_smiling_eyes:

@pierre-gilles,

Ich habe gesehen, dass du #2651 gemerged hast, also habe ich die Konflikte im PR #2652 gelöst

@Terdious danke für die PR, das ist gut, aber ich finde, dass wir die spezifischen Daten jedes Jobtyps zu sehr mit dem generischen Job-Objekt koppeln.

Ich schlage eine korrigierte PR vor:

Sag mir, ob dir das gut erscheint :slight_smile:

@pierre-gilles,

Ich habe alles gelesen, ich bin voll und ganz mit der Analyse und dem Fix einverstanden, es ist sauberer als ein „Alles-ist-drin“-Katalog. Danke dir!!

Ich habe den Test bei mir zu Hause vor dem Release in die Produktion (heute Nachmittag) durchgeführt:

Ich habe 40 Millionen Zustände, aber ich bin wohl nie in den Bug-Fall geraten ^^

Zum Glück ^^
Genauso mit 400 Millionen, ich hatte nur 20 davon ^^ Aber ich lösche nie Ausrüstung / Funktionen :wink: :sweat_smile:

Aber @Will_71 hatte enorm viel davon!!