feat: /status fuer die Statusseite -- und der Fehler, den es dabei gefunden hat

/health gab es und bleibt, wie es ist: app.get('/health', c => c.json({ok:true})).
Diese Zeile beweist genau eines -- der Prozess nimmt Anfragen an. Daran haengt
der HEALTHCHECK des Containers, und DORT ist billig richtig: eine schwere
Pruefung, die bei einer langsamen Platte einmal ausfaellt, liesse Docker den
Container neu starten, also genau dann, wenn er unter Last steht.

Fuer eine Statusseite ist das zu duenn -- sie stuende auf Gruen, waehrend die
Platte voll ist und kein Upload mehr angenommen wird.

/status sieht deshalb wirklich nach: Datenbank (eine echte Abfrage, nicht "die
Datei ist da"), Platte (schreiben UND wieder loeschen, der einzige Beweis),
Ausliefern (eine zufaellige Datei aus der Datenbank auf der Platte nachmessen),
Bestand, Platz und Sicherung. 200 wenn der Dienst sein Geschaeft tut, 503 wenn
nicht; ?streng=1 laesst auch eine Beeintraechtigung rot werden -- WELCHES von
beiden richtig ist, weiss nur, wer die Statusseite betreibt.

Oeffentlich, aber wortkarg: keine Dateizahlen, Groessen, Pfade, Tokennamen,
Benutzer. Und mit einer Zehn-Sekunden-Bremse -- ein oeffentlicher Endpunkt, der
auf die Platte schreibt, waere sonst ein Verstaerker.

UND DABEI FIEL EIN FEHLER IN MEINEM EIGENEN ZURUECKSPIEL-SKRIPT AUF.

Der harte Weg sollte an einem Wegwerf-Container geprueft werden. Der traf
zufaellig auf ein GEBRAUCHTES Volume, und die Zahlen waren eindeutig:

    media.db aus dem Archiv, mit altem WAL daneben :     0 Zeilen
    dieselbe Datei ohne die beiden Begleiter       :  4452 Zeilen
    Dateien auf der Platte                        :  4452

zurueckspielen.ps1 entfernte media.db, aber NICHT media.db-wal und
media.db-shm. Die liegen bei einem echten Zurueckspielen immer da -- der
laufende Dienst arbeitet im WAL-Modus. SQLite spielt das WAL der ALTEN
Datenbank ueber die NEUE, und heraus kommt der schlimmste denkbare Zustand: der
Dienst kommt hoch, /health ist gruen, die Mediathek ist leer, waehrend alle
Dateien danebenliegen.

Drei Konsequenzen:

1. Die Aufraeumzeile steht jetzt an EINER Stelle und nimmt media.db-wal,
   media.db-shm und *.tmp mit. Uebung und Ernstfall fahren denselben Befehl --
   zwei Fassungen waeren zwei, von denen die geuebte die harmlosere ist.

2. Die Uebung TAEUSCHT JETZT EINE BESTEHENDE INSTALLATION VOR, bevor sie
   zurueckspielt: Container starten, warten bis media.db-wal daliegt, stoppen,
   und erst dann einspielen. In ein leeres Volume zu spielen probt den Fall,
   der nie eintritt.

3. /status erkennt den Zustand selbst -- "kein Eintrag in der Datenbank, aber
   Dateien auf der Platte". Am kaputten Container gemessen:

       /health sagt:  HTTP 200
       /status sagt:  HTTP 503

Der geuebte Lauf danach, ueber eine vorgetaeuschte Installation:

    im Volume liegt jetzt: files media.db media.db-shm media.db-wal
    4452 Medieneintraege, 4452 Dateien -- gleich viele
    ok  items/shushi.png · items/weedbud_1.png · items/cc-castella.png
    Die Uebung ist bestanden.

Gefunden beim Ueben und nicht im Ernstfall. Genau dafuer gibt es sie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 00:04:26 +02:00
co-authored by Claude Opus 5
parent 338f8e59cf
commit 3f706b27e1
6 changed files with 469 additions and 5 deletions
+76
View File
@@ -838,6 +838,82 @@ Container an, ersetzt `media.db`, `files/` und `papierkorb/`, **löscht
Galerie zeigte die Vorschau einer Datei, die dort nicht mehr liegt), startet
wieder und zählt selbst nach.
### ✅ Fertig — /status für die Statusseite, und ein Fehler, den es dabei fand
**Es gab schon `/health`**, und es bleibt, wie es ist:
```ts
app.get('/health', (c) => c.json({ ok: true }))
```
Diese Zeile beweist genau eines: der Prozess nimmt Anfragen an. Daran hängt der
`HEALTHCHECK` des Containers, und **dort** ist billig richtig — eine schwere
Prüfung, die bei einer langsamen Platte einmal ausfällt, ließe Docker den
Container neu starten, also genau dann, wenn er unter Last steht.
Für eine Statusseite ist das zu dünn: sie stünde auf Grün, während die Platte
voll ist. `/status` sieht deshalb wirklich nach — Datenbank (echte Abfrage),
Platte (schreiben *und wieder löschen*), Ausliefern (zufällige Datei nachmessen),
Bestand, Platz, Sicherung. **200** wenn der Dienst sein Geschäft tut, **503**
wenn nicht; `?streng=1` lässt auch eine Beeinträchtigung rot werden.
Öffentlich, aber wortkarg: keine Dateizahlen, Größen, Pfade, Tokennamen oder
Benutzer. Und mit einer 10-Sekunden-Bremse — ein öffentlicher Endpunkt, der auf
die Platte schreibt, wäre sonst ein Verstärker.
**Beide Wege gemessen**, der weiche am laufenden Dienst (Sicherungszeitpunkt auf
40 Stunden gesetzt und wieder zurück):
```
stand: beeintraechtigt · /status -> 200 · /status?streng=1 -> 503
```
#### Und dabei fiel ein Fehler in meinem eigenen Zurückspiel-Skript auf
Der harte Weg sollte an einem Wegwerf-Container geprüft werden. Der traf
zufällig auf ein **gebrauchtes** Volume — und zeigte:
| | Zeilen in `media.db` |
|---|---|
| mit den alten `media.db-wal` / `-shm` daneben | **0** |
| dieselbe Datei ohne sie | **4452** |
| Dateien auf der Platte | **4452** |
`zurueckspielen.ps1` entfernte `media.db`, aber **nicht die beiden
WAL-Begleiter**. Die liegen bei einem echten Zurückspielen immer da — der
laufende Dienst arbeitet im WAL-Modus. SQLite spielt das WAL der *alten*
Datenbank über die *neue*, und heraus kommt der schlimmste denkbare Zustand:
**der Dienst kommt hoch, `/health` ist grün, die Mediathek ist leer** — während
alle Dateien danebenliegen.
Zwei Konsequenzen:
1. Die Aufräumzeile steht jetzt an **einer** Stelle und nimmt `media.db-wal`,
`media.db-shm` und `*.tmp` mit. Übung und Ernstfall fahren denselben Befehl —
zwei Fassungen wären zwei, von denen die geübte die harmlosere ist.
2. **Die Übung täuscht jetzt eine bestehende Installation vor**, bevor sie
zurückspielt. In ein leeres Volume zu spielen probt den Fall, der nie
eintritt.
```
==> Eine bestehende Installation vortaeuschen
im Volume liegt jetzt: files media.db media.db-shm media.db-wal
==> Zurueckspielen -- mit DEMSELBEN Befehl wie der Ernstfall
4452 Medieneintraege · 4452 Dateien -- gleich viele
ok items/shushi.png · items/weedbud_1.png · items/cc-castella.png
Die Uebung ist bestanden.
```
3. Und `/status` erkennt diesen Zustand jetzt selbst. Am kaputten Container
gemessen:
```
/health sagt: HTTP 200
/status sagt: HTTP 503 kein Eintrag in der Datenbank, aber Dateien auf der Platte
```
Genau dafür gibt es die Übung: gefunden beim Üben, nicht im Ernstfall.
### ⬜ Als Nächstes
**Der Vergleichsmaßstab ist weg.** Am 11.08.2026 sind die Lite-Container