backup: gegenpruefen, nachholen, und endlich Bescheid sagen
Befund 2, 3 und 4 aus docs/befunde-2026-08-12.md. Befund 1 bleibt offen, Befund
5 war falsch und ist zurueckgezogen.
DER BOT SAGT JETZT BESCHEID. src/melden.js ist neu und enthaelt, was vorher in
watchdog.js eingeschlossen war: dmAdmin. Genau deshalb hat alles andere im Bot
geschwiegen oder in die Konsole geschrieben -- und eine Konsolenzeile in einem
Container liest niemand.
Dazu dmAdminEinmalig: meldet nur bei ZUSTANDSWECHSEL. Sonst wuerde eine
Pruefung, die alle zehn Minuten laeuft, denselben Ausfall alle zehn Minuten
melden, und nach der dritten DM liest man sie nicht mehr. Der Merker steht in
den Einstellungen und nicht im Arbeitsspeicher -- ein Bot, der nach jedem
Update neu startet, haette sonst nach jedem Update wieder eine frische Meinung.
Gemessen gegen eine KOPIE der Datenbank, sechs Schritte, alle wie beabsichtigt.
DER WACHHUND AUF last_backup. pruefeSicherung() meldet, wenn die letzte
Sicherung aelter als 26 Stunden ist, wenn sie fehlgeschlagen ist, oder wenn es
nie eine gab. Im Fehlerfall steht NICHT last_backup als Zeitpunkt im Embed: der
wird nur bei Erfolg gesetzt, dort staende also der letzte GUTE Lauf, und das
liesse die Sicherung frischer aussehen als sie ist.
DER TAG FAELLT NICHT MEHR AUS. Vorher "if (now.getHours() !== 3) return" -- wer
waehrend dieser einen Stunde unten war, hatte den Tag verloren, und ein Bot,
der nach jedem Update neu startet, ist genau dieser Fall. Jetzt zaehlt nur: es
ist nach 03:00 und heute war noch keine.
DAS ARCHIV WIRD AUSGEPACKT UND GEZAEHLT. integrity_check plus Tabellenzahl
gegen die laufende Datenbank. Faellt das durch, wird das Archiv GELOESCHT (im
Sicherungsordner saehe es sonst aus wie eine Sicherung), die Rotation laeuft
nicht, und last_backup bleibt stehen.
An echten Archiven gemessen, mit zwei Gegenproben, damit die Pruefung nicht nur
"ja" sagen kann:
2026-08-10 817 KB 54 Tabellen 86 ms
2026-08-11 886 KB 54 Tabellen 64 ms
2026-08-12 970 KB 55 Tabellen 78 ms (laufend: 55)
halbes gzip -> "unexpected end of file"
Muell -> "incorrect header check"
Die 54 gegen 55 sind kein Fehler, sondern eine gewachsene Tabelle zwischen dem
11. und dem 12. Verglichen wird zeitgleich, also stoert das nicht -- wissen
sollte man es, bevor jemand alte Archive gegen die heutige Zahl haelt.
BEFUND 5 WAR FALSCH. pruneMessageCache wird sehr wohl aufgerufen, taeglich, in
mod-tools.js:239 -- und stand schon zum Zeitpunkt der Durchsicht dort. Gezaehlt
wurden "Aufrufe ausserhalb von db.js", und die Sammel-Importzeile ist als
Import durchgegangen, waehrend der Aufruf zwanzig Zeilen tiefer nicht mitkam.
Das ist genau der Fehler, den zu vermeiden dieser Bericht dasteht; die anderen
vier sind deshalb einzeln nachgemessen worden und stimmen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+116
-12
@@ -128,22 +128,39 @@ Ein Backup, das man nie zurückgespielt hat, ist keins.
|
||||
|
||||
---
|
||||
|
||||
## 5 · `pruneMessageCache` wird nie aufgerufen
|
||||
## ~~5 · `pruneMessageCache` wird nie aufgerufen~~ — FALSCH, zurückgezogen am 12.08.2026
|
||||
|
||||
```
|
||||
prunePlayerHistory 1 Aufruf ausserhalb db.js
|
||||
pruneWatchdogHistory 1
|
||||
pruneHeartbeat 1
|
||||
pruneIncidents 1
|
||||
pruneMessageCache 0 <-
|
||||
**Dieser Befund war falsch.** Der Aufruf steht in `src/bot/mod-tools.js:239`, in
|
||||
`registerModTools`, mit eigenem Kommentar — und er stand schon zum Zeitpunkt der
|
||||
Durchsicht dort (nachgesehen in `git show 1808b7c:src/bot/mod-tools.js`):
|
||||
|
||||
```js
|
||||
const aufraeumen = () => {
|
||||
const weg = pruneMessageCache(Math.max(0, tuning('modlog_cache_days')));
|
||||
if (weg > 0) console.log(`[modlog] ${weg} alte Nachrichten vergessen`);
|
||||
};
|
||||
aufraeumen();
|
||||
setInterval(aufraeumen, 86_400_000);
|
||||
```
|
||||
|
||||
Exakt dasselbe Muster, das in `d4rk_media` bei `pruneEvents` gefunden wurde: die
|
||||
Funktion ist da, die Aufbewahrungsfrist ist dokumentiert, der Aufruf fehlt.
|
||||
Täglich, mit Frist aus der Feineinstellung. **Es ist nichts zu tun.**
|
||||
|
||||
**Heute harmlos** — die Tabelle hat 18 Zeilen. Aber die Frist greift nicht, und
|
||||
wenn der Nachrichten-Zwischenspeicher je stärker benutzt wird, wächst er ohne
|
||||
Ende.
|
||||
Wie es passieren konnte: gezählt wurden „Aufrufe außerhalb von `db.js`" — und
|
||||
`mod-tools.js` importiert die Funktion in einer Sammelzeile mit fünf anderen
|
||||
Namen. Beim Zählen ist die Zeile als Import durchgegangen und der Aufruf
|
||||
zwanzig Zeilen weiter unten nicht mitgezählt worden.
|
||||
|
||||
**Das ist genau der Fehler, den zu vermeiden dieser Bericht dasteht:** eine
|
||||
plausible Zahl, die niemand am Gegenstand nachgeprüft hat. Die anderen vier
|
||||
Befunde sind deshalb am 12.08.2026 alle noch einmal einzeln nachgemessen worden
|
||||
— sie stimmen:
|
||||
|
||||
| Befund | Nachgemessen |
|
||||
|---|---|
|
||||
| 1 · Sicherung ohne sicheren Ort | `backup_channel_id` ist **leer** — der Offsite-Zweig lief nie |
|
||||
| 2 · Ausbleiben fällt niemandem auf | `last_backup` kommt an drei Stellen vor: schreiben, Tagesbremse, anzeigen. **Nirgends ein Vergleich mit heute.** |
|
||||
| 3 · Zu groß endet in der Konsole | `console.warn` in `backup.js`, unverändert |
|
||||
| 4 · Archiv nie gegengeprüft | kein Auspacken, kein Öffnen, kein Zählen im ganzen Modul |
|
||||
|
||||
---
|
||||
|
||||
@@ -189,3 +206,90 @@ eine Kopie neben dem Original, deren Ausfall unbemerkt bliebe.
|
||||
Der billigste Schritt ist `backup_channel_id` zu setzen — ein Klick, und der
|
||||
vorgesehene Weg funktioniert. Der solide Schritt ist derselbe wie bei
|
||||
`d4rk_media`: abholen, prüfen, in die Nextcloud, und ein Wachhund darauf.
|
||||
|
||||
---
|
||||
|
||||
## Was am 12.08.2026 daraus gebaut wurde
|
||||
|
||||
**Befund 2, 3 und 4 sind erledigt** — Befund 1 zur Hälfte (siehe unten).
|
||||
|
||||
### Der Bot sagt jetzt Bescheid
|
||||
|
||||
`src/melden.js` ist neu und enthält das, was vorher in `watchdog.js`
|
||||
eingeschlossen war: `dmAdmin`. Deshalb hat alles andere im Bot geschwiegen oder
|
||||
in die Konsole geschrieben — **eine Konsolenzeile in einem Container liest
|
||||
niemand.**
|
||||
|
||||
Dazu `dmAdminEinmalig(client, schluessel, zustand, …)`: meldet nur, wenn sich
|
||||
der Zustand *geändert* hat. Ohne das würde eine Prüfung, die alle zehn Minuten
|
||||
läuft, denselben Ausfall alle zehn Minuten melden — nach der dritten DM liest
|
||||
man sie nicht mehr. Der Merker steht in den Einstellungen und nicht im
|
||||
Arbeitsspeicher: ein Bot, der nach jedem Update neu startet, hätte sonst nach
|
||||
jedem Update wieder eine frische Meinung.
|
||||
|
||||
Nachgemessen gegen eine **Kopie** der Datenbank, sechs Schritte:
|
||||
|
||||
```
|
||||
1. Ausfall zum ersten Mal gebaut: 1 Merker: "alt:…T03"
|
||||
2. derselbe Ausfall noch zweimal gebaut: 0 Merker: "alt:…T03"
|
||||
3. ANDERER Ausfall gebaut: 1 Merker: "fehler:…T09"
|
||||
4. wieder in Ordnung (null) gebaut: 0 Merker: ""
|
||||
5. derselbe Ausfall danach erneut gebaut: 1 Merker: "alt:…T03"
|
||||
```
|
||||
|
||||
### Der Wachhund auf `last_backup`
|
||||
|
||||
`pruefeSicherung(client)` läuft im selben Zehn-Minuten-Takt wie der Planer und
|
||||
meldet, wenn die letzte Sicherung älter als **26 Stunden** ist, wenn die letzte
|
||||
fehlgeschlagen ist, oder wenn es noch nie eine gab.
|
||||
|
||||
Beim Fehlerfall steht **nicht** `last_backup` als Zeitpunkt im Embed: der wird
|
||||
nur bei Erfolg gesetzt, dort stünde also der letzte *gute* Lauf, und das ließe
|
||||
die Sicherung frischer aussehen, als sie ist. Der Zeitpunkt des Fehlschlags
|
||||
steht getrennt daneben (`last_backup_fehler_at`).
|
||||
|
||||
### Der Tag fällt nicht mehr aus
|
||||
|
||||
Vorher:
|
||||
|
||||
```js
|
||||
if (now.getHours() !== 3) return;
|
||||
```
|
||||
|
||||
Wer während dieser **einen Stunde** unten war, hatte den Tag verloren — und ein
|
||||
Bot, der nach jedem Update neu startet, ist genau dieser Fall. Jetzt zählt nur
|
||||
noch: es ist nach 03:00 und heute war noch keine. Der Lauf wird also nachgeholt.
|
||||
|
||||
### Das Archiv wird ausgepackt und gezählt
|
||||
|
||||
Nach dem Zippen wird das Archiv wieder ausgepackt, die Datenbank darin geöffnet,
|
||||
`PRAGMA integrity_check` gefahren und die Tabellen gezählt — gegen die
|
||||
**laufende** Datenbank. Fällt das durch, wird das Archiv **gelöscht** (im
|
||||
Sicherungsordner sähe es sonst aus wie eine Sicherung), die Rotation läuft
|
||||
nicht, und `last_backup` bleibt stehen.
|
||||
|
||||
An den echten Archiven gemessen, und mit zwei Gegenproben, damit die Prüfung
|
||||
nicht nur „ja" sagen kann:
|
||||
|
||||
```
|
||||
laufende Datenbank: 55 Tabellen
|
||||
|
||||
2026-08-10 817 KB 54 Tabellen, 86 Einstellungen 86 ms
|
||||
2026-08-11 886 KB 54 Tabellen, 86 Einstellungen 64 ms
|
||||
2026-08-12 970 KB 55 Tabellen, 86 Einstellungen 78 ms
|
||||
|
||||
halbes gzip -> abgelehnt: "unexpected end of file"
|
||||
Müll -> abgelehnt: "incorrect header check"
|
||||
```
|
||||
|
||||
Die 54 gegen 55 sind übrigens kein Fehler, sondern eine **gewachsene** Tabelle
|
||||
zwischen dem 11. und dem 12. Verglichen wird zeitgleich — Archiv gegen die
|
||||
Datenbank, aus der es gerade entstanden ist —, also stört das nicht. Wissen
|
||||
sollte man es trotzdem, bevor jemand alte Archive gegen die heutige Zahl hält.
|
||||
|
||||
### Was offen bleibt: Befund 1
|
||||
|
||||
Die Sicherung liegt **weiterhin im selben Volume** wie die Datenbank. Der
|
||||
eingebaute Ausweg (`backup_channel_id`) braucht eine Kanal-ID, die nur du geben
|
||||
kannst — ein privater Kanal, in dem der Bot Dateien anhängen darf. Ein Klick in
|
||||
Setup → Einstellungen, und der Zweig läuft.
|
||||
|
||||
Reference in New Issue
Block a user