From 1f8f3efc72f473885d74e919de7acdd7659c81ad Mon Sep 17 00:00:00 2001 From: mika kuns Date: Fri, 7 Aug 2026 10:12:27 +0200 Subject: [PATCH] docs: record that the sqlite busy-timeout finding was wrong, drop stale RunCreated mention --- docs/explore-notes/worker-task-pipeline.md | 2 +- ...2026-08-07-ui-reaktivitaet-und-listen-performance-design.md | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/explore-notes/worker-task-pipeline.md b/docs/explore-notes/worker-task-pipeline.md index 743b46de..306ed028 100644 --- a/docs/explore-notes/worker-task-pipeline.md +++ b/docs/explore-notes/worker-task-pipeline.md @@ -124,7 +124,7 @@ read-only "## Reference files" section. - `TaskMergeService` — conflict resolution for worktree merges. **Hub/** -- `HubBroadcaster` — single SignalR broadcast point (TaskStarted/TaskUpdated/TaskMessage/RunCreated…). +- `HubBroadcaster` — single SignalR broadcast point (TaskStarted/TaskUpdated/TaskMessage/WorktreeUpdated…). - `WorkerHub` — SignalR hub + client methods. **Agents/** diff --git a/docs/superpowers/specs/2026-08-07-ui-reaktivitaet-und-listen-performance-design.md b/docs/superpowers/specs/2026-08-07-ui-reaktivitaet-und-listen-performance-design.md index ad4e994e..0c2fc220 100644 --- a/docs/superpowers/specs/2026-08-07-ui-reaktivitaet-und-listen-performance-design.md +++ b/docs/superpowers/specs/2026-08-07-ui-reaktivitaet-und-listen-performance-design.md @@ -29,7 +29,7 @@ Das eigentliche Problem: **ein einziger verlorener Event ist permanent.** Der ei Dazu zwei kleinere Befunde: - **Race im Delta-Pfad.** `OnWorkerTaskUpdated` ist `async void` und hängt an *zwei* Events (`TaskUpdatedEvent` und `WorktreeUpdatedEvent`, `TasksIslandViewModel.cs:117-118`). Der Full-Reload-Zweig ist per `_loadCts` gegen Überholen abgesichert, der Delta-Zweig nicht — ein älterer Read kann einen neueren überschreiben. -- **Kein Busy-Timeout konfiguriert.** Die Connection-Strings beider Prozesse sind blanke `Data Source=…` (`src/ClaudeDo.App/Program.cs:100-101`, `src/ClaudeDo.Worker/Program.cs:60-61`). Ohne Timeout schlägt ein seltener `SQLITE_BUSY` sofort als Exception durch, statt kurz zu warten — das erhöht die Wahrscheinlichkeit von Loch 1. Achtung: `PRAGMA busy_timeout` ist **per Connection** und wird — anders als `journal_mode=WAL` — *nicht* in der DB-Datei persistiert. Es in `ClaudeDoDbContext.MigrateAndConfigure` zu setzen würde nur die Startup-Connection betreffen und wäre wirkungslos; es gehört in den Connection-String (`Default Timeout=`), den Microsoft.Data.Sqlite auf den Busy-Handler abbildet. +- ~~**Kein Busy-Timeout konfiguriert.**~~ **Widerlegt (2026-08-07, empirisch geprüft).** Die Vermutung war, die blanken Connection-Strings (`src/ClaudeDo.App/Program.cs:95`, `src/ClaudeDo.Worker/Program.cs:61`) ließen einen `SQLITE_BUSY` sofort durchschlagen. Das stimmt nicht: Microsoft.Data.Sqlite 8.0.11 setzt `DefaultTimeout` **von sich aus auf 30 Sekunden**, mit oder ohne das Keyword — gemessen an `SqliteConnectionStringBuilder("Data Source=x.db").DefaultTimeout` → `30`, ebenso `SqliteConnection.DefaultTimeout` und `SqliteCommand.CommandTimeout`. Ein Contention-Test (Writer hält 2s, zweiter Writer parallel) zeigt, dass der zweite wartet und nach ~2030 ms durchkommt, statt zu werfen. Der ursprünglich dafür gemachte Commit `f62dbb9` war ein No-op mit irreführendem Kommentar und wurde mit `ac58679` zurückgenommen. Die tatsächliche Absicherung gegen transiente Lesefehler leistet der Retry im Delta-Pfad, nicht ein Timeout. - **`RunCreated` ist ein totes Event.** Wird in `TaskRunner.cs:358` gesendet, hat aber keinen einzigen Abonnenten in der UI. ### Performance: der Engpass ist das Rendering, nicht die Datenbank @@ -97,7 +97,6 @@ Unabhängig von Phase 2 und 3, kann sofort starten. | Fix | Ort | |---|---| | `catch { }` ersetzen durch Log + einmaligen Retry. **Kein** Footer-Error — das ist ein Hintergrund-Refresh, keine Nutzeraktion. | `TasksIslandViewModel.cs:224` | -| `Default Timeout=30` in beide Connection-Strings (nicht als PRAGMA — siehe Analyse) | `App/Program.cs:100-101`, `Worker/Program.cs:60-61` | | Catch-Block ruft `_state.FailAsync` (das selbst broadcastet), statt nur zu loggen; `OperationCanceledException` bleibt ausgenommen | `QueueService.cs:349-352` | | `WorktreeUpdated` nach dem Insert broadcasten | `Runner/WorktreeManager.cs:103` | | `TaskUpdated` nach dem Insert broadcasten | `Online/OnlineSyncService.cs:131` |