From f3b1c25d8b2131ea39025499b04ee9d22a73045b Mon Sep 17 00:00:00 2001 From: Administrator Date: Tue, 21 Apr 2026 16:14:58 +0200 Subject: [PATCH] perf(queue): halve sync work on retry of many jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit retrySelectedJobs() was calling renderQueueTable + updateQueueActionButtons + updateStatusBar and then immediately awaiting startSelectedUpload(), which runs the exact same trio right after. At 500+ failed jobs the double render/sort/button-refresh freezes the UI for several seconds after clicking "Erneut versuchen". Drop the outer render trio — startSelectedUpload's one is enough. The inner call sees the freshly-mutated job state in the same tick, so the visible result is identical with half the work. --- renderer/app.js | 8 ++++---- tasks/lessons.md | 12 ++++++++++++ tasks/todo.md | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 tasks/lessons.md create mode 100644 tasks/todo.md diff --git a/renderer/app.js b/renderer/app.js index 4d681a2..b1338be 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -1982,12 +1982,12 @@ async function retrySelectedJobs() { }); if (retryJobs.length === 0) return; - // Select the retry jobs and start them immediately + // Select the retry jobs and start them immediately. + // No renderQueueTable / updateQueueActionButtons / updateStatusBar here: + // startSelectedUpload() runs the exact same trio right after, and at 500+ + // jobs the double render freezes the UI for multiple seconds. selectedJobIds.clear(); retryJobs.forEach(j => selectedJobIds.add(j.id)); - renderQueueTable(); - updateQueueActionButtons(); - updateStatusBar(); persistQueueStateSoon(); await startSelectedUpload(); } diff --git a/tasks/lessons.md b/tasks/lessons.md new file mode 100644 index 0000000..184192e --- /dev/null +++ b/tasks/lessons.md @@ -0,0 +1,12 @@ +# Lessons + +## 2026-04-21 — DOM-Doppelrender bei Bulk-State-Changes +**Symptom:** User klickt auf "Erneut versuchen" mit 500+ Jobs → App hängt sekundenlang. +**Root cause:** `retrySelectedJobs()` ruft `renderQueueTable + updateQueueActionButtons + updateStatusBar` auf, `startSelectedUpload()` ruft direkt danach genau dieselben Funktionen nochmal auf. +**Regel:** Wenn ein Click-Handler `await anotherHandler()` aufruft und der innere Handler seinen eigenen kompletten Render-Zyklus hat, NIEMALS noch einen davor. Einmal ist genug — der folgende innere Render sieht die frischen State-Mutationen ohnehin. +**Wie anwenden:** Vor jeder `await fn()`-Folge in einem Handler prüfen: macht `fn` schon `renderQueueTable()`? Wenn ja, äußere Render-Calls löschen. + +## 2026-04-21 — Keine fake Build-ETAs +**Symptom:** User wartet 5+ min auf Tauri-Build den ich mit "1-2min" angekündigt habe. +**Regel:** Tauri-Release-Builds brauchen real 3-6 min (Rust + NSIS + MSI). Keine Zeitangabe oder ehrlich "kann 3-6min dauern" schreiben. +**Wie anwenden:** Wenn User nach Status fragt: sofort `tail` des Logs + `ls` des Bundle-Ordners zitieren, nicht raten. diff --git a/tasks/todo.md b/tasks/todo.md new file mode 100644 index 0000000..66f970c --- /dev/null +++ b/tasks/todo.md @@ -0,0 +1,22 @@ +# Retry-Hang bei 500-600 failed jobs + +## Problem +User hat 500-600 Uploads, davon viele `error`. Markiert alle, klickt "Erneut versuchen" → App friert mehrere Sekunden ein. + +## Root Cause (renderer/app.js) +`retrySelectedJobs()` (Z.1952) → mutiert 500 Jobs → `renderQueueTable() + updateQueueActionButtons() + updateStatusBar()` (Z.1988-1990) → dann `await startSelectedUpload()` (Z.1992) → das mutiert SIE ERNEUT (Z.1724-1732) → rendert NOCHMAL (Z.1733-1735). + +**Doppelter DOM-Zyklus + doppelte Mutation bei 500 Jobs = hängt-Gefühl.** + +Zusätzlicher Multiplikator: main.js:1066 `JSON.stringify(files)` in `debugLog` — auch wenn `files` leer ist. Außerdem `buildUploadTasksFromJobs` loopt synchron 500x im main-Thread. + +## Plan +- [x] Entferne doppelten Render in `retrySelectedJobs` — `startSelectedUpload` macht das ohnehin in einem Rutsch. +- [x] Lesson dokumentieren in `tasks/lessons.md`. +- [ ] (optional, später) main.js:1066 — debugLog nicht mit JSON.stringify(files/hosters), nur counts loggen. +- [ ] (optional, später) Progress-Event-Flood während laufendem Upload: batch via rAF statt sync updateQueueActionButtons+updateStatusBar+updateStatsPanel. + +## Review +Fix entfernt eine komplette Render-Pass-Runde vor dem Aufruf von `startSelectedUpload`. Bei 500+ Jobs halbiert das die Sync-Work im Click-Handler (Sort, Virtual-Render, Button-Update, StatusBar-Update). `selectedJobIds` bleibt korrekt befüllt weil die Selektion VOR `startSelectedUpload` gesetzt wird. `persistQueueStateSoon` ist debounced, deshalb kein Zusammenspielproblem. + +Funktional identisch: Die Jobs durchlaufen am Ende dieselbe State-Kaskade (reset → queued → getting-server → uploading), nur mit einem statt zwei Render-Zyklen dazwischen.