fix(mounts): Wache, die die Freigabe nach einem Rebuild von selbst zurueckholt
Ampel / ampel (push) Successful in 28s
Ampel / ampel (push) Successful in 28s
Dreimal in Folge reproduziert, jetzt bei JEDEM Deploy: Nach `docker compose up -d --build` ist die CIFS-Freigabe tot. `mount` meldet Rueckgabewert 0, /proc/mounts zeigt genau eine korrekt aussehende Schicht, die Erreichbarkeits-Probe antwortet direkt nach dem Mount sogar - und Sekunden spaeter laeuft jeder Zugriff in die Zeitgrenze. Derselbe Ablauf ein bis zwei Minuten spaeter stellt sie zuverlaessig her (POST /storage-mounts/rippy/repair, mehrfach belegt). Die Ursache liegt am NAS und ist nicht gefunden. Aber die Wirkung ist teuer: Nach jedem Update war jeder Rip auf die NAS kaputt, ohne dass irgendwo etwas davon zu sehen war - und der Commander haette es jedes Mal von Hand richten muessen. Wenn die Heilung bekannt und billig ist, gehoert sie automatisiert, auch ohne die Ursache zu kennen. Die Wache sieht jede Minute nach und verbindet stumme Freigaben neu. Zwei Dinge sind dabei wichtiger als die Heilung selbst: 1. NIE waehrend ein Job laeuft. Neu verbinden heisst `umount -l`; mitten in einem Rip oder Encode waere das ein Datenverlust. Die Wache steht still, solange irgendein Job nicht durch ist - auch bei einem wartenden, der jeden Moment anlaufen kann (db.hat_arbeit). 2. Gemeldet wird nur der UEBERGANG. Ist das NAS ausgeschaltet, waere ein Log je Minute ein Wasserfall. Der Zustand steht in /health/vorraete, damit man sehen kann, dass die Wache lebt - dieselbe Lehre wie heute Nachmittag beim stillen except. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -210,6 +210,24 @@ def delete_worker(name: str) -> None:
|
||||
conn.execute(workers.delete().where(workers.c.name == name))
|
||||
|
||||
|
||||
def hat_arbeit() -> bool:
|
||||
"""True, wenn IRGENDEIN Job noch nicht durch ist (egal auf welchem Gerät).
|
||||
|
||||
Gebraucht von der Mount-Wache: Eine Freigabe neu zu verbinden bedeutet ein
|
||||
`umount -l` — mitten in einem laufenden Rip oder Encode wäre das ein
|
||||
Datenverlust. `pending` zählt bewusst mit: so ein Job kann jeden Moment
|
||||
anlaufen.
|
||||
"""
|
||||
with engine.connect() as conn:
|
||||
zeile = conn.execute(
|
||||
select(jobs.c.id)
|
||||
.where(jobs.c.status.in_(
|
||||
("pending", "running", "ripping", "transcoding", "canceling")))
|
||||
.limit(1)
|
||||
).first()
|
||||
return zeile is not None
|
||||
|
||||
|
||||
def has_active_job(device: str) -> bool:
|
||||
"""True, wenn auf dem Gerät ein Job läuft oder wartet (Eject-Schutz)."""
|
||||
with engine.connect() as conn:
|
||||
|
||||
Reference in New Issue
Block a user