feat(worker): der externe Worker wird erwachsen - Log in Rippy, Anzeige, Slots
Ampel / ampel (push) Successful in 28s
Ampel / ampel (push) Successful in 28s
Commander 26.07.2026: "der externe Encoder Worker ist ein bisschen duenn - der koennte noch viel mehr." Drei Punkte, alle am Tray. 1. LOG IN RIPPY STATT TXT-DATEI (ausdruecklich gewuenscht). Das Tray schrieb sein Log nach %LOCALAPPDATA% und oeffnete es im Editor - wer wissen wollte, warum der Worker nichts tut, musste sich an den PC setzen. Neue Bruecke (logbruecke.py) meldet die wichtigen Zeilen nach Rippy, Quelle "w:<name>", und die Logs-Seite hat jetzt Knoepfe je Quelle: "was macht mein PC" ist ein Klick. Der Filter konnte Quellen schon immer, es gab nur keinen Knopf. Durchgelassen wird WENIG und mit Grund: Die Job-Meldungen stehen laengst in Rippy (tasks.py schreibt sie selbst). Es fehlte, was DANEBEN passiert und den Worker unbrauchbar macht, ohne dass ein Job existiert - hochgefahren oder nicht, Verbindung zu Redis/Postgres, Abstuerze. Alles andere fliegt weg: Celery ist bei --loglevel=info gespraechig, die logs-Tabelle hat keine Aufraeumung, und ein zugemuelltes Log ist so unbrauchbar wie keins. Dazu eine Drossel (30 Zeilen/Minute), die MELDET, wieviel sie verschluckt hat. Zeilenformat woertlich aus dem laufenden Container abgenommen (Celery 5.4.0). Die lokale Datei bleibt - sie ist genau dann die einzige Auskunft, wenn Rippy nicht erreichbar ist. 2. DAS TRAY ZEIGT, WAS LAEUFT. Vorher stand dort "laeuft" oder "gestoppt" - auf einer Maschine, die stundenlang an einem Film rechnet, ist das keine Auskunft. Jetzt Titel, Prozent und Restzeit, geholt von Rippys /jobs. Bewusst dieselbe Quelle wie das Dashboard, damit im Tray nicht eine zweite, abweichende Schaetzung steht. Dazu: Windows schlaeft nicht mehr mitten im Encode ein (SetThreadExecutionState, ohne ES_DISPLAY_REQUIRED - der Bildschirm darf ausgehen). Die Sperre wird zurueckgenommen, sobald nichts laeuft, und auch bei einem harten Ende des Trays - sonst schlaeft der PC nie wieder ein und niemand weiss warum. 3. MEHRERE ENCODES GLEICHZEITIG. Der Worker lief fest mit --pool=solo und nahm genau EINEN Auftrag an. Der Installer fragt die Zahl jetzt (GUI: Feld neben dem Namen, mit der erkannten Kernzahl daneben), Vorbelegung ab 12 Kernen zwei, sonst einer: HandBrake nutzt schon alle Kerne, aber x265 skaliert nicht linear. Auf Windows gibt es keinen prefork-Pool (kein fork) - deshalb --pool=threads, was hier passt, weil die Arbeit ein Kind-Prozess ist und der Thread nur wartet. GUI-Layout headless gerendert und angesehen (nichts ueberlappt, 16 Kerne korrekt erkannt), beide .ps1 mit echtem PowerShell 5.1 geprueft, BOM und CRLF erhalten, .exe neu gebaut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,10 +70,28 @@ export default function LogsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const filteredLogs = filter === 'all'
|
||||
? logs
|
||||
const filteredLogs = filter === 'all'
|
||||
? logs
|
||||
: logs.filter(log => log.level === filter || log.source === filter)
|
||||
|
||||
/*
|
||||
* Quellen zum Anklicken (Commander-Wunsch 26.07.2026: „bessere Log-Ansichten
|
||||
* — kein txt file, direkt von Rippy Logs").
|
||||
*
|
||||
* Der Filter konnte Quellen schon immer, es gab nur keinen Knopf dafür — man
|
||||
* musste die Zeilen mit dem Auge durchsuchen. Seit dieser Runde meldet auch
|
||||
* der externe Windows-Worker hierher (worker/logbruecke.py, Quelle „w:<name>"),
|
||||
* und damit wird die Auswahl erst richtig nützlich: „was macht mein PC?" ist
|
||||
* ein Klick.
|
||||
*
|
||||
* Die Liste wird aus den WIRKLICH vorhandenen Zeilen gebaut, nicht aus einer
|
||||
* festen Aufzählung — sonst fehlt jede neue Maschine.
|
||||
*/
|
||||
const quellen = [...new Set(logs.map(l => l.source).filter(Boolean))].sort()
|
||||
|
||||
// „w:tobisnicerpc" ist als Knopfbeschriftung unschön.
|
||||
const quelleLabel = (q: string) => q.startsWith('w:') ? `Worker ${q.slice(2)}` : q
|
||||
|
||||
const stats = {
|
||||
info: logs.filter(l => l.level === 'info').length,
|
||||
warning: logs.filter(l => l.level === 'warning').length,
|
||||
@@ -162,6 +180,25 @@ export default function LogsPage() {
|
||||
{f === 'all' ? 'Alle' : getLevelLabel(f)}
|
||||
</button>
|
||||
))}
|
||||
|
||||
{quellen.length > 1 && (
|
||||
<>
|
||||
<span className="text-xs font-medium text-slate-500 dark:text-slate-400 mx-2">Quelle:</span>
|
||||
{quellen.map(q => (
|
||||
<button
|
||||
key={q}
|
||||
onClick={() => setFilter(q)}
|
||||
className={`px-3 py-1 rounded-full text-xs font-medium transition-all ${
|
||||
filter === q
|
||||
? 'bg-indigo-500 text-white font-bold shadow-md shadow-indigo-500/20'
|
||||
: 'bg-slate-200/70 dark:bg-slate-800 text-slate-700 dark:text-slate-300 hover:bg-slate-300 dark:hover:bg-slate-700'
|
||||
}`}
|
||||
>
|
||||
{quelleLabel(q)}
|
||||
</button>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="max-h-[600px] overflow-y-auto">
|
||||
|
||||
Reference in New Issue
Block a user