videowatch-Queue: bei Verbindungs- und Konfigurationsfehlern pausieren statt Versuche zu verbrauchen #53

Closed
opened 2026-10-16 12:44:32 +00:00 by alf · 5 comments
Owner

Problem

Wenn ein Dienst fehlt, den jedes Video braucht (LM Studio/Splash oder Whisper nicht erreichbar), probiert die Queue jedes Video dreimal und markiert es dann als failed. Am 2026-10-16 liefen so vier Videos in knapp zwei Minuten durch ($TMPDIR/videowatch-logs/queue-*.log: je 3 Versuche, 5 s Pause, Ende Queue abgeschlossen: 0 erledigt, 4 fehlgeschlagen). Die Queue-Datei wanderte nach completed/, die Einträge müssen von Hand per „Erneut versuchen" zurückgesetzt werden.

Die Wiederholungen sind in diesem Fall sinnlos: Der Fehler hängt nicht am Video, sondern an der Umgebung, und beim nächsten Video ist er derselbe.

Ursache

_process_item in skills/videowatch/process_queue.py kennt nur den Exit-Code von watch_local.py (MAX_ATTEMPTS = 3, RETRY_DELAY_SECONDS = 5). Es unterscheidet nicht zwischen „dieses Video ist kaputt" und „die Infrastruktur fehlt".

Vorschlag

  • watch_local.py beendet sich bei Infrastrukturfehlern (LLM-Endpunkt oder Whisper nicht erreichbar) mit einem eigenen Exit-Code, zum Beispiel 75 (EX_TEMPFAIL), statt mit 1. Das ist deterministischer als der Abgleich von Fehlertext.
  • process_queue.py zählt solche Fehler nicht als Versuch, lässt das Item auf pending und pausiert die ganze Queue (global.pause), statt zum nächsten Video zu gehen.
  • Iris meldet die Pause mit Grund (lastError, Benachrichtigung), und die Queue läuft nach dem Aufheben der Pause oder nach Erreichbarkeit weiter.

Offen

  • Soll die Queue von selbst weiterlaufen, sobald der Dienst wieder antwortet (Probe-Aufruf), oder erst auf Knopfdruck?
  • Welche Fehler gelten als Infrastruktur: LLM-Endpunkt, Whisper, yt-dlp-Netzwerk, Plattenplatz?
  • Betrifft Mac- und Linux-Server gleich, wenn das Verhalten im Worker liegt (der Linux-Server nutzt dasselbe process_queue.py, das habe ich nicht geprüft).

Zusammenhang: iris/Iris#50 (dort wurde der Fehlergrund in lastError ergänzt).

## Problem Wenn ein Dienst fehlt, den **jedes** Video braucht (LM Studio/Splash oder Whisper nicht erreichbar), probiert die Queue jedes Video dreimal und markiert es dann als `failed`. Am 2026-10-16 liefen so vier Videos in knapp zwei Minuten durch (`$TMPDIR/videowatch-logs/queue-*.log`: je 3 Versuche, 5 s Pause, Ende `Queue abgeschlossen: 0 erledigt, 4 fehlgeschlagen`). Die Queue-Datei wanderte nach `completed/`, die Einträge müssen von Hand per „Erneut versuchen" zurückgesetzt werden. Die Wiederholungen sind in diesem Fall sinnlos: Der Fehler hängt nicht am Video, sondern an der Umgebung, und beim nächsten Video ist er derselbe. ## Ursache `_process_item` in `skills/videowatch/process_queue.py` kennt nur den Exit-Code von `watch_local.py` (`MAX_ATTEMPTS = 3`, `RETRY_DELAY_SECONDS = 5`). Es unterscheidet nicht zwischen „dieses Video ist kaputt" und „die Infrastruktur fehlt". ## Vorschlag - `watch_local.py` beendet sich bei Infrastrukturfehlern (LLM-Endpunkt oder Whisper nicht erreichbar) mit einem eigenen Exit-Code, zum Beispiel 75 (`EX_TEMPFAIL`), statt mit 1. Das ist deterministischer als der Abgleich von Fehlertext. - `process_queue.py` zählt solche Fehler nicht als Versuch, lässt das Item auf `pending` und pausiert die ganze Queue (`global.pause`), statt zum nächsten Video zu gehen. - Iris meldet die Pause mit Grund (`lastError`, Benachrichtigung), und die Queue läuft nach dem Aufheben der Pause oder nach Erreichbarkeit weiter. ## Offen - Soll die Queue von selbst weiterlaufen, sobald der Dienst wieder antwortet (Probe-Aufruf), oder erst auf Knopfdruck? - Welche Fehler gelten als Infrastruktur: LLM-Endpunkt, Whisper, yt-dlp-Netzwerk, Plattenplatz? - Betrifft Mac- und Linux-Server gleich, wenn das Verhalten im Worker liegt (der Linux-Server nutzt dasselbe `process_queue.py`, das habe ich nicht geprüft). Zusammenhang: iris/Iris#50 (dort wurde der Fehlergrund in `lastError` ergänzt).
Author
Owner

PR #65 gemergt: feat(videowatch): Queue pausiert, wenn der LLM-Server fehlt, statt Versuche zu verbrauchen (iris/Iris#53)

watch_local.py prüft den LLM-Server vor dem Download und beendet sich bei Ausfall oder fehlendem
Modell mit Exit-Code 75 (EXIT_SERVICE_UNAVAILABLE). process_queue.py zählt dafür keinen Versuch,
lässt das Item vorn in der Queue, schaltet die globale Pause ein und meldet den Grund per
Benachrichtigung; nach dem Wiedereinschalten läuft dasselbe Video weiter. SKILL.md angepasst,
8 neue Tests.

Co-Authored-By: Claude Sonnet 5.5 noreply@anthropic.com
alf/2ndbrain#65

Commits:

  • feat(videowatch): Queue pausiert, wenn der LLM-Server fehlt, statt Versuche zu verbrauchen (iris/Iris#53)
PR #65 gemergt: feat(videowatch): Queue pausiert, wenn der LLM-Server fehlt, statt Versuche zu verbrauchen (iris/Iris#53) watch_local.py prüft den LLM-Server vor dem Download und beendet sich bei Ausfall oder fehlendem Modell mit Exit-Code 75 (EXIT_SERVICE_UNAVAILABLE). process_queue.py zählt dafür keinen Versuch, lässt das Item vorn in der Queue, schaltet die globale Pause ein und meldet den Grund per Benachrichtigung; nach dem Wiedereinschalten läuft dasselbe Video weiter. SKILL.md angepasst, 8 neue Tests. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> https://forgejo.lewerken.duckdns.org/alf/2ndbrain/pulls/65 Commits: - feat(videowatch): Queue pausiert, wenn der LLM-Server fehlt, statt Versuche zu verbrauchen (iris/Iris#53)
Author
Owner

PR #12 gemergt: feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)

Co-Authored-By: Claude Sonnet 5.5 noreply@anthropic.com
iris/2ndbrain-ios#12

Commits:

  • feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)
PR #12 gemergt: feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> https://forgejo.lewerken.duckdns.org/iris/2ndbrain-ios/pulls/12 Commits: - feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)
Author
Owner

PR #56 gemergt: feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)

Co-Authored-By: Claude Sonnet 5.5 noreply@anthropic.com
#56

Commits:

  • feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)
PR #56 gemergt: feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> https://forgejo.lewerken.duckdns.org/iris/Iris/pulls/56 Commits: - feat(videowatch): Grund auch bei wartenden Queue-Einträgen anzeigen (iris/Iris#53)
Author
Owner

Stand 2026-10-16: umgesetzt (alf/2ndbrain PR #65, Anzeige in iris/Iris und iris/2ndbrain-ios)

Verhalten jetzt

  • watch_local.py prüft den LLM-Server vor dem Download (client.models.list()). Fehlt er, oder ist kein Modell geladen (nur wenn kein --model übergeben wurde), endet der Lauf mit Exit-Code 75 (EXIT_SERVICE_UNAVAILABLE, download.py). Vorher kam der Fehler erst nach dem Download, und mit gesetztem --model (zum Beispiel Splash) gar nicht vorab. Die Meldung heißt jetzt LLM-Server nicht erreichbar (<URL>): ….
  • process_queue.py zählt für Code 75 keinen Versuch, lässt das Item auf pending an der Spitze, schaltet die globale Pause ein (global.pause) und schickt die Benachrichtigung „videowatch pausiert: . Nach dem Beheben die Verarbeitung in der Queue wieder einschalten."
  • Der Worker bleibt am Leben und wartet in _wait_if_paused. Der Schalter „Verarbeitung aktiv" löscht die Datei, danach läuft dasselbe Video ohne Neustart weiter.
  • Beide Apps zeigen den Grund (lastError) jetzt auch bei wartenden Einträgen, nicht nur bei fehlgeschlagenen.
  • SKILL.md: die beiden Fehlerabschnitte (Server nicht erreichbar, kein Modell geladen) sind angepasst.

Entscheidung zu den offenen Fragen aus dem Issue

  • Fortsetzen auf Knopfdruck, nicht automatisch per Probe-Aufruf: einfacher, deterministisch, und der Nutzer behält die Kontrolle (derselbe Schalter wie bisher).
  • Als Infrastruktur gelten nur LLM-Endpunkt nicht erreichbar und kein Modell geladen. Whisper nicht: ein ausfallender Remote-Whisper fällt in der Kaskade ohnehin auf mlx-whisper bzw. faster-whisper zurück und ist kein Abbruchgrund. yt-dlp-Netzwerkfehler bleiben pro Video wiederholbar.

Geprüft

  • 16 Unit-Tests (8 davon seit #54, 3 neu für diese Änderung): Code 75 zählt keinen Versuch, die Pause-Datei entsteht und die Benachrichtigung enthält Grund und Handlungshinweis, Erfolg liefert Code 0.
  • Echter Lauf watch_local.py mit nicht erreichbarer LLM-Adresse: Exit-Code 75, Meldung LLM-Server nicht erreichbar (http://127.0.0.1:9/v1): Connection error., kein Arbeitsverzeichnis, kein Download.
  • Echter Lauf process_queue.py in einem Temp-Verzeichnis: nach 5 s global.pause, Item pending mit 0 Versuchen und dem Grund in lastError; nach dem Löschen der Pause-Datei läuft derselbe Eintrag erneut an und pausiert wieder.
  • Builds von Iris.xcodeproj und der iOS-App sind erfolgreich.

Nicht geprüft / Grenzen

  • Kein Durchlauf in der echten Iris-Oberfläche (Pause, Schalter, Anzeige). Die laufende Iris.app hat die Anzeige erst nach einem Neubau; die Worker-Änderung ist über den Symlink schon aktiv.
  • Die Pause gilt für alle Queues (global.pause ist global). Das passt, weil der LLM-Server von allen gemeinsam genutzt wird, ist aber nicht pro Queue einstellbar.
  • watch_local.py meldet den Fehlschlag selbst weiter per Benachrichtigung (nötig, damit der Watchdog den Lauf nicht als Absturz meldet). Je Pause erscheinen deshalb „fehlgeschlagen: " und „pausiert".
  • Der Linux-Server nutzt dasselbe process_queue.py (er startet es aus dem Skill-Ordner). Ob und wann der Skill dort aktualisiert ist, habe ich nicht geprüft; ein Test gegen den Linux-Server fehlt.
  • Fehlt der LLM-Server, nachdem das Video schon läuft (zum Beispiel mitten in der Analyse), greift die neue Pause nicht: die Prüfung passiert nur am Anfang des Laufs.
## Stand 2026-10-16: umgesetzt (alf/2ndbrain PR #65, Anzeige in iris/Iris und iris/2ndbrain-ios) **Verhalten jetzt** - `watch_local.py` prüft den LLM-Server **vor** dem Download (`client.models.list()`). Fehlt er, oder ist kein Modell geladen (nur wenn kein `--model` übergeben wurde), endet der Lauf mit Exit-Code 75 (`EXIT_SERVICE_UNAVAILABLE`, `download.py`). Vorher kam der Fehler erst nach dem Download, und mit gesetztem `--model` (zum Beispiel Splash) gar nicht vorab. Die Meldung heißt jetzt `LLM-Server nicht erreichbar (<URL>): …`. - `process_queue.py` zählt für Code 75 keinen Versuch, lässt das Item auf `pending` an der Spitze, schaltet die globale Pause ein (`global.pause`) und schickt die Benachrichtigung „videowatch pausiert: <Grund>. Nach dem Beheben die Verarbeitung in der Queue wieder einschalten." - Der Worker bleibt am Leben und wartet in `_wait_if_paused`. Der Schalter „Verarbeitung aktiv" löscht die Datei, danach läuft **dasselbe** Video ohne Neustart weiter. - Beide Apps zeigen den Grund (`lastError`) jetzt auch bei wartenden Einträgen, nicht nur bei fehlgeschlagenen. - `SKILL.md`: die beiden Fehlerabschnitte (Server nicht erreichbar, kein Modell geladen) sind angepasst. **Entscheidung zu den offenen Fragen aus dem Issue** - Fortsetzen **auf Knopfdruck**, nicht automatisch per Probe-Aufruf: einfacher, deterministisch, und der Nutzer behält die Kontrolle (derselbe Schalter wie bisher). - Als Infrastruktur gelten nur LLM-Endpunkt nicht erreichbar und kein Modell geladen. Whisper nicht: ein ausfallender Remote-Whisper fällt in der Kaskade ohnehin auf mlx-whisper bzw. faster-whisper zurück und ist kein Abbruchgrund. yt-dlp-Netzwerkfehler bleiben pro Video wiederholbar. **Geprüft** - 16 Unit-Tests (8 davon seit #54, 3 neu für diese Änderung): Code 75 zählt keinen Versuch, die Pause-Datei entsteht und die Benachrichtigung enthält Grund und Handlungshinweis, Erfolg liefert Code 0. - Echter Lauf `watch_local.py` mit nicht erreichbarer LLM-Adresse: Exit-Code 75, Meldung `LLM-Server nicht erreichbar (http://127.0.0.1:9/v1): Connection error.`, kein Arbeitsverzeichnis, kein Download. - Echter Lauf `process_queue.py` in einem Temp-Verzeichnis: nach 5 s `global.pause`, Item `pending` mit 0 Versuchen und dem Grund in `lastError`; nach dem Löschen der Pause-Datei läuft derselbe Eintrag erneut an und pausiert wieder. - Builds von `Iris.xcodeproj` und der iOS-App sind erfolgreich. **Nicht geprüft / Grenzen** - Kein Durchlauf in der echten Iris-Oberfläche (Pause, Schalter, Anzeige). Die laufende Iris.app hat die Anzeige erst nach einem Neubau; die Worker-Änderung ist über den Symlink schon aktiv. - Die Pause gilt für **alle** Queues (`global.pause` ist global). Das passt, weil der LLM-Server von allen gemeinsam genutzt wird, ist aber nicht pro Queue einstellbar. - `watch_local.py` meldet den Fehlschlag selbst weiter per Benachrichtigung (nötig, damit der Watchdog den Lauf nicht als Absturz meldet). Je Pause erscheinen deshalb „fehlgeschlagen: <Quelle>" und „pausiert". - Der Linux-Server nutzt dasselbe `process_queue.py` (er startet es aus dem Skill-Ordner). Ob und wann der Skill dort aktualisiert ist, habe ich nicht geprüft; ein Test gegen den Linux-Server fehlt. - Fehlt der LLM-Server, nachdem das Video schon läuft (zum Beispiel mitten in der Analyse), greift die neue Pause nicht: die Prüfung passiert nur am Anfang des Laufs.
Author
Owner

Geschlossen auf Wunsch von Alf. Umgesetzt in alf/2ndbrain #65 (Worker, Exit-Code 75, Pause) sowie in iris/Iris und iris/2ndbrain-ios (Grund auch bei wartenden Einträgen). Nicht Teil dieses Issues geblieben: Prüfung des LLM-Servers mitten im Lauf, Test gegen den Linux-Server, Pause pro Queue statt global.

Geschlossen auf Wunsch von Alf. Umgesetzt in alf/2ndbrain #65 (Worker, Exit-Code 75, Pause) sowie in iris/Iris und iris/2ndbrain-ios (Grund auch bei wartenden Einträgen). Nicht Teil dieses Issues geblieben: Prüfung des LLM-Servers mitten im Lauf, Test gegen den Linux-Server, Pause pro Queue statt global.
alf closed this issue 2026-10-16 13:35:39 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
iris/Iris#53
No description provided.