Przejdź do treści

Etap 30 — Cache-first kiosk (wydajność)

Zaimplementowane + WDROŻONE 2026-06-17 (kiosk 1.5.71)

Ekrany kiosku rysują z lokalnego cache NATYCHMIAST, a sieć dociąga w tle (stale-while-revalidate) — koniec czekania na rundę do backendu (i na 8 s timeout na słabym łączu) przy każdym otwarciu. Logowanie i media już tak działały; teraz tak samo wszystkie listy.

Geneza — audyt strategii odczytu

Etap-29 dorobił offline jako fallback (najpierw API, dopiero przy błędzie sieci → cache). To znaczy: na zdrowym łączu każdy ekran czekał ~100–300 ms na backend, a na migającym łączu do 8 s (timeout) zanim cokolwiek pokazał. Audyt:

Przepływ Było Jest
Logowanie PIN/RFID ✅ cache-first (bcrypt lokalnie) bez zmian
Zdjęcia / PDF ✅ cache-first (etap-28) bez zmian
Wydawanie (katalog) ❌ network-first cache-first
Odbiór paczek ❌ network-first cache-first
Inwentaryzacja ❌ network-first cache-first
Uzupełnianie ❌ network-first cache-first
Wyszukiwarka odbiorcy ❌ network-first cache-first
Machine-info ⚠️ snapshot + refresh w tle bez zmian (już ok)

Wzorzec (stale-while-revalidate)

1. render z offlineRepo/SQLite od razu (~10–50 ms) → _loading = false 2. w tle: api.get → podmień listę + (katalog) re-cache snapshotu 3. brak sieci → zostaje cache, BEZ spinnera

Per-ekran

  • Wydawanie (dispense_screen._load/_refresh): dispenseCatalogOffline natychmiast → online /dispense/me/catalog w tle (cacheUserDispenseSnapshot). Flaga _refreshing tłumi baner „offline — tylko uprawnione" podczas odświeżania (żeby nie mignął).
  • Inwentaryzacja (inventory_screen): lista produktów cache-first + revalidate; _pickProduct buduje kolumny z cache od razu (start sesji bez czekania) — OCC guard (etap-29 5.1) pilnuje dryfu baseline przy zapisie.
  • Uzupełnianie (replenish_screen): lista cache-first + revalidate.
  • Wyszukiwarka odbiorcy (deposit_recipient_screen): lokalne dopasowania z cached_users natychmiast → pełny katalog z serwera w tle.
  • Odbiór (user_menu._goPickup + PickupScreen): otwiera ekran z cache od razu; PickupScreen._refreshList w initState re-syncuje z /pickup/by-user w tle i zdejmuje nieaktualne pozycje — NIE nadpisuje wiersza, na którym operator jest w trakcie akcji (it.busy). Adresuje obawę v1.1.1 (stare tombstone) bez blokowania otwarcia. Brak cache → backend decyduje parcels vs no-parcels.

Znane kompromisy (świadome)

  • Odbiór: nieaktualna pozycja może mignąć na ~200 ms zanim re-sync ją zdejmie; sam odbiór i tak re-waliduje online przy otwarciu skrytki.
  • Wydawanie: cache-first renderuje listę offline (tylko w pełni uprawnione, w stanie), a online refresh dokłada pozostałe (zablokowane/wyszarzone) — lista „rośnie" po ~200 ms. Akcja wydania jest zawsze walidowana serwerowo, więc nieświeży render nie szkodzi.
  • Inwentaryzacja: zestaw skrytek (kolumny) jest z cache (sync co 2 min) — świeżo dodana skrytka pojawi się po następnym syncu; quantity-drift łapie OCC guard.

Wzorzec na przyszłość: nowe ekrany kiosku czytające listy → zawsze cache-first + revalidate, nie network-first.

Powiązane