[Opstart][P1] Vóór het eerste frame — en dus vóór het venster op Windows — draait onbegrensd synchroon werk #2626

Closed
opened 2026-10-28 16:31:39 +00:00 by brenno · 0 comments
Owner

Symptoom

"De app start niet": na dubbelklikken gebeurt er een tijd niets, of helemaal niets. Wie dan nog eens klikt, start een tweede proces (#2627).

Oorzaak

Op Windows wordt het venster pas getoond bij het eerste frame (windows/runner/flutter_window.cpp:40, SetNextFrameCallback → Show()). Alles wat vóór dat frame op de UI-isolate gebeurt, is voor de gebruiker onzichtbaar wachten. Vóór runApp (lib/main.dart:51-79) gebeurt:

  1. AssetStaging.pruneStale() (regel 54) — "mag de start niet ophouden", maar doet dat wel: het is unawaited, maar pruneStale (lib/services/asset_staging.dart:86) loopt elke bewaarde sessiemap (7 dagen) recursief en synchroon af (listSync(recursive: true) + statSync() per bestand, _newestModified, regel 128-142). Tussen twee mappen die blijven staan zit geen await, dus dit is één ononderbroken blok op de UI-isolate. Het loopt precies wanneer main verderop wacht op het lexicon, dus vóór het eerste frame. De kosten groeien met het aantal geïmporteerde media in de afgelopen week; op Windows betaalt elke stat ook de virusscanner.
  2. Het gezondheidslexicon (regel 74): 2 MB JSON, 63 808 termen, ontleed en geïndexeerd op de UI-isolate. Gemeten: 57 ms op een snelle Mac (debug); op een trage laptop een veelvoud.
  3. configureNativeWindow() en AssetStaging.initialize() — kort, maar zonder tijdslimiet.

Niets hiervan logt een mijlpaal (#2618), dus een trage of hangende start is achteraf niet te onderscheiden van een crash.

Voorgestelde oplossing

  1. pruneStale echt asynchroon: dir.list() / stat() async (of het geheel in Isolate.run) en pas na het eerste frame starten — het is huishouding.
  2. Het lexicon in Isolate.run ontleden en indexeren (de await vóór runApp mag blijven, de redenering in main.dart daarover klopt), of het lexicon vooraf als compacte binaire index bundelen.
  3. Overweeg het venster direct te tonen met de bestaande "OciDeck wordt gestart…"-weergave en het werk daarachter te doen; dan ziet de gebruiker altijd dát de app start.
  4. Een opstartwaakhond: is het eerste frame na 10 s niet bereikt, log dan welke stap nog loopt.

Wat overeind moet blijven

De lexicon-garantie (geen scan vóór het lexicon geladen is), het opruimen van verlopen staging en de rechtenbeperking op Linux.

Toets

  • Unit: pruneStale op een stagingmap met 20 sessies × 500 bestanden roept geen *Sync-API aan (injecteerbaar bestandssysteem of tellende wrapper).
  • Release-rookproef: tijd tot eerste frame vastleggen (logmijlpaal) en een plafond zetten.

Onderdeel van de prestatie- en stabiliteitsinspectie van 28-10-2026 (EPIC #2637).

## Symptoom "De app start niet": na dubbelklikken gebeurt er een tijd niets, of helemaal niets. Wie dan nog eens klikt, start een tweede proces (#2627). ## Oorzaak Op Windows wordt het venster pas getoond **bij het eerste frame** (`windows/runner/flutter_window.cpp:40`, `SetNextFrameCallback → Show()`). Alles wat vóór dat frame op de UI-isolate gebeurt, is voor de gebruiker onzichtbaar wachten. Vóór `runApp` (`lib/main.dart:51-79`) gebeurt: 1. **`AssetStaging.pruneStale()`** (regel 54) — "mag de start niet ophouden", maar doet dat wel: het is `unawaited`, maar `pruneStale` (`lib/services/asset_staging.dart:86`) loopt elke bewaarde sessiemap (7 dagen) **recursief en synchroon** af (`listSync(recursive: true)` + `statSync()` per bestand, `_newestModified`, regel 128-142). Tussen twee mappen die blijven staan zit geen `await`, dus dit is één ononderbroken blok op de UI-isolate. Het loopt precies wanneer `main` verderop wacht op het lexicon, dus vóór het eerste frame. De kosten groeien met het aantal geïmporteerde media in de afgelopen week; op Windows betaalt elke `stat` ook de virusscanner. 2. **Het gezondheidslexicon** (regel 74): 2 MB JSON, 63 808 termen, ontleed en geïndexeerd op de UI-isolate. Gemeten: 57 ms op een snelle Mac (debug); op een trage laptop een veelvoud. 3. `configureNativeWindow()` en `AssetStaging.initialize()` — kort, maar zonder tijdslimiet. Niets hiervan logt een mijlpaal (#2618), dus een trage of hangende start is achteraf niet te onderscheiden van een crash. ## Voorgestelde oplossing 1. `pruneStale` echt asynchroon: `dir.list()` / `stat()` async (of het geheel in `Isolate.run`) en pas **na het eerste frame** starten — het is huishouding. 2. Het lexicon in `Isolate.run` ontleden en indexeren (de `await` vóór `runApp` mag blijven, de redenering in `main.dart` daarover klopt), of het lexicon vooraf als compacte binaire index bundelen. 3. Overweeg het venster direct te tonen met de bestaande "OciDeck wordt gestart…"-weergave en het werk daarachter te doen; dan ziet de gebruiker altijd dát de app start. 4. Een **opstartwaakhond**: is het eerste frame na 10 s niet bereikt, log dan welke stap nog loopt. ## Wat overeind moet blijven De lexicon-garantie (geen scan vóór het lexicon geladen is), het opruimen van verlopen staging en de rechtenbeperking op Linux. ## Toets - Unit: `pruneStale` op een stagingmap met 20 sessies × 500 bestanden roept geen `*Sync`-API aan (injecteerbaar bestandssysteem of tellende wrapper). - Release-rookproef: tijd tot eerste frame vastleggen (logmijlpaal) en een plafond zetten. Onderdeel van de prestatie- en stabiliteitsinspectie van 28-10-2026 (EPIC #2637).
brenno 2026-10-29 12:19:45 +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
LibreKAT/Ocideck#2626
No description provided.