fix(zombies): "running" fehlte - ein abgestuerzter RIP wurde NIE gefunden
Ampel / ampel (push) Successful in 30s
Ampel / ampel (push) Successful in 30s
Der Commander: "Ausserdem ist gerade mitten im Rip das Laufwerk ausgegangen...
glaube ich zumindest." Gemessen war es etwas anderes, und der Fund ist groesser
als der Vorfall.
WAS MESSBAR WAR:
Job 2182d525 status=running progress=12 (Rip gestartet 14:00:24)
makemkvcon laeuft NICHT (per /proc geprueft, PID gegengeprueft)
Rohdatei 5.167.382.528 Bytes, waechst in 10 s nicht
Laufwerk Status 4 (Disc drin), /dev/sr0 + /dev/sg1 da
Worker-Start 14:07:02 <- mein `docker compose up -d --build`
Das Laufwerk ist also NICHT ausgegangen. Der Rip wurde von MEINEM Deploy
getoetet: `up -d --build` baut den worker-Container neu, und der laufende Rip
stirbt mit ihm. Genau davor warnt der SAVEPOINT seit v3.18 - die Warnung half
nichts, weil sie niemand liest und nichts sie prueft.
DER EIGENTLICHE FUND: Die Zombie-Erkennung lief um 14:09:04 und meldete
`{'geprueft': 0, 'aufgeraeumt': []}` - obwohl der tote Job direkt vor ihr lag.
Ursache:
ARBEITS_STATI = ("ripping", "transcoding", "canceling") # zombies.py
db.update_job(job_id, status="running", ...) # tasks.py - der Rip
Der Rip setzt "running", gesucht wurde "ripping". Dieser Wert steht
ausschliesslich in Celerys Task-META und NIE in einer Job-Zeile (nachgeprueft:
kein einziger Schreiber im ganzen Baum). Die Zombie-Erkennung aus v3.14 wurde
gebaut, um genau einen abgestuerzten Rip zu finden - und hat ihn nie gesehen.
Besonders tueckisch: `geprueft: 0` sah bei jedem Worker-Start wie "nachgesehen,
alles gesund" aus, waehrend sie nach einem Status suchte, den es nicht gibt.
Deshalb blieb der Job auf "processing 12 %" stehen - mit einer Restzeit-Schaetzung
von 1 h 30 min obendrauf, die es fuer einen toten Prozess nicht geben duerfte.
GEBAUT:
* "running" in ARBEITS_STATI.
* Ein Test, der das Auseinanderlaufen MECHANISCH verhindert: Er liest tasks.py,
sammelt jeden Status, den der Worker per db.update_job in eine Job-Zeile
schreibt, und verlangt, dass jeder davon entweder ein Arbeitsstatus oder ein
Endzustand ist. Ein Kommentar haette das nicht verhindert.
* GET /health/arbeit + eine Sperre in deploy.sh: Laeuft ein Job, bricht der
Deploy ab (uebersteuerbar mit RIPPY_TROTZDEM=1 - dann ist es eine
Entscheidung und kein Versehen). Ein Satz Code gegen eine verlorene Stunde.
* Server-Status zeigt jetzt die eingehaengten FREIGABEN mit freiem Platz, nicht
nur die Container-Platte (Commander-Wunsch). Genau dort liegen die Rohdaten,
und bei externem Encoden muessen sie dort liegen - wer wissen wollte, ob noch
Platz fuer eine Disc ist, sah die falsche Zahl.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -308,6 +308,33 @@ async def health_check():
|
||||
return {"status": "ok", "service": "api"}
|
||||
|
||||
|
||||
@app.get("/health/arbeit")
|
||||
async def health_arbeit():
|
||||
"""Läuft gerade ein Job? — die Frage VOR einem Deploy.
|
||||
|
||||
⚠️ Warum es das gibt (26.07.2026, selbst verursacht): Ein
|
||||
`docker compose up -d --build` baut den worker-Container neu und tötet damit
|
||||
einen laufenden Rip. Genau das ist passiert — mitten in einem Blu-ray-Rip,
|
||||
bei 12 %, nach 5,1 GB. Im SAVEPOINT stand die Warnung „nicht deployen,
|
||||
während ein Rip läuft" schon; sie half nichts, weil niemand sie las und
|
||||
nichts sie prüfte.
|
||||
|
||||
Jetzt fragt `deploy.sh` hier nach und bricht ab. Ein Satz Code gegen eine
|
||||
verlorene Stunde.
|
||||
"""
|
||||
def sammle():
|
||||
laufend = [
|
||||
{"id": z["id"], "status": z["status"], "progress": z.get("progress") or 0,
|
||||
"titel": z.get("title") or ""}
|
||||
for z in db.list_jobs()
|
||||
if z.get("status") in ("pending", "running", "ripping",
|
||||
"transcoding", "canceling")
|
||||
]
|
||||
return {"arbeit": bool(laufend), "jobs": laufend}
|
||||
|
||||
return await asyncio.to_thread(sammle)
|
||||
|
||||
|
||||
@app.get("/health/vorraete")
|
||||
async def health_vorraete():
|
||||
"""Laufen die Hintergrund-Schleifen wirklich? (Diagnose, kein UI-Endpunkt)
|
||||
|
||||
Reference in New Issue
Block a user