super_cache
Produktionsreifer LRU- und TTL-Cache für Flutter und Dart, mit mehrschichtiger Speicherung und Schutz vor Mehrfachanfragen.
Eine Cache-Bibliothek für Flutter und Dart, die doppelte API-Aufrufe verhindert, in O(1) verdrängt und die Trefferquote live ausgibt. Der Kern kommt ohne externe Abhängigkeiten aus.
super_cache ist eine Cache-Bibliothek für Flutter und Dart, veröffentlicht auf pub.dev unter MIT. Der Kern hat keine externen Abhängigkeiten und läuft unter Android, iOS, Web, macOS, Windows und Linux.
Sie entstand aus einem konkreten Problem: Drei Widgets, die im selben Moment denselben Nutzer anfordern, lösen drei identische Netzwerkaufrufe aus. super_cache bündelt sie zu einem. Ein Schlüssel, der bereits unterwegs ist, bedeutet eine Anfrage, und alle Aufrufer warten auf dasselbe Future.
Darum herum liegen ein LRU in O(1) mit TTL, drei Cache-Schichten, die Einträge bei einem Treffer nach oben befördern, und Metriken, die sich zur Laufzeit ablesen lassen.
Hauptfunktionen
LRU in O(1) mit TTL
Eine Hash-Map zusammen mit einer doppelt verketteten Liste hält get, put und Verdrängung unabhängig von der Größe bei konstanter Zeit. TTL arbeitet pro Eintrag absolut oder gleitend, sodass ein Sitzungstoken und eine Produktliste im selben Cache nach unterschiedlichen Regeln ablaufen können.
Schutz vor Mehrfachanfragen
Gleichzeitige Lesezugriffe auf einen bereits laufenden Schlüssel teilen sich ein Future, statt jeweils eine eigene Anfrage zu stellen. Drei gleichzeitig eingehängte Widgets erzeugen einen Netzwerkaufruf.
Drei Schichten mit Beförderung
Arbeitsspeicher, ein mit AES-256-GCM verschlüsselter Puffer und Festplattenspeicher mit einer Datei pro Eintrag. Ein Treffer auf der Platte befördert den Eintrag nach oben, der zweite Zugriff ist damit ein Speicherzugriff.
Strategien pro Aufrufstelle
CacheAside liest verzögert, WriteThrough holt immer frische Daten, und RefreshAhead liefert den veralteten Wert, während im Hintergrund aktualisiert wird. Die Strategie ist ein Argument, keine globale Einstellung.
Beobachtbare Metriken
Trefferquote, Anzahl der Verdrängungen und Anzahl der Einträge gibt es als Momentaufnahme oder als Broadcast-Stream. Das Cache-Verhalten lässt sich damit zur Laufzeit beobachten, statt es aus Netzwerkprotokollen abzuleiten.
Deterministische Tests
Ein Begleitpaket liefert FakeCache und ManualClock, sodass TTL-Ablauf und Verdrängung geprüft werden können, ohne die Testsuite schlafen zu legen.
Tech-Stack
Architektur
Drei Schichten liegen hinter einem einzigen Orchestrator. L1 ist ein LRU im Arbeitsspeicher, bei einem Treffer synchron. L2 ist ein mit AES-256-GCM verschlüsselter Puffer im Speicher. L3 ist Festplattenspeicher mit einer Datei pro Eintrag und Integritätsprüfung. Ein Lesezugriff fällt von L1 über L2 nach L3 durch und befördert das Gefundene wieder nach oben, sodass wiederholte Zugriffe im Speicher landen.
Die API liefert FutureOr<V?> statt immer ein Future. Ein L1-Treffer löst synchron auf und gibt die Kontrolle nie an die Event-Loop ab. Genau das hält einen Speicherzugriff bei etwa 0,04 Mikrosekunden, statt für einen bereits vorliegenden Wert einen asynchronen Sprung zu bezahlen.
Die Verdrängung lässt sich über die Anzahl der Einträge steuern oder, mit einem sizeEstimator, über Bytes. Ein evictFraction()-Haken erlaubt es außerdem, einen Teil des Caches freizugeben, wenn die Plattform Speicherdruck meldet, statt auf die Beendigung zu warten.
Das Kernpaket hängt von nichts außerhalb des SDK ab. Verschlüsselung, Festplattenpersistenz und Test-Doubles liegen in eigenen Begleitpaketen, sodass eine App, die nur einen LRU im Speicher braucht, flutter_secure_storage nicht mitzieht.
Herausforderungen & Lösungen
Die schwierigen Probleme, und wie ich sie gelöst habe.
Einen Speichertreffer aus der Event-Loop heraushalten
Ehrlich bleiben, was die verschlüsselte Schicht schützt
Weitere Projekte
Interesse an einer Zusammenarbeit?
Ich bin immer offen für Gespräche über neue Projekte und Möglichkeiten.