restate / v1.0.0
Zuverlässigkeit by Design
Was restate garantiert, wenn der Speicher langsam ist, ausfällt oder fehlt – und wie du die gemeldeten Fehler liest.
Auf dieser Seite
Die GarantienGeordnete SpeichervorgängeAusprobierenWenn das Laden fehlschlägtSpeichern und schließenKein Speicher verfügbarGespeicherte Daten validieren und migrierenEigenen Speicher mitbringenLimits und TimeoutsFehlercodesDie Garantien
Dieses Verhalten ist Teil des 1.0-Vertrags und durch die Tests des Pakets abgedeckt.
| Situation | Was restate tut |
|---|---|
Mehrere Speichervorgänge hintereinander | Führt sie pro Store der Reihe nach aus; ein in der Warteschlange wartender Speichervorgang schreibt den neuesten Wert. |
Ein Datensatz konnte nicht geladen werden | autoSave und Sammel-Speichervorgänge überspringen ihn mit LOAD_FAILED; nur ein explizites save() ersetzt ihn. |
Komponente wird während eines Speichervorgangs unmountet | Der angeforderte Speichervorgang wird fertig; spätere Schreibvorgänge in den zerstörten Store werden ignoriert. |
Speicher ist nicht verfügbar | Der Store arbeitet im Arbeitsspeicher, status().available ist false, Speichervorgänge werden abgelehnt. |
Ein Adapter hängt | Die Operation läuft nach operationTimeoutMs ab, und spätere Arbeit wartet, bis der Adapter fertig ist. |
Zu viel ausstehende Arbeit | Neue Operationen werden mit QUEUE_FULL abgelehnt, statt unbegrenzt anzuwachsen. |
Geordnete Speichervorgänge
Operationen eines Stores überschneiden sich nie. Ein Speichervorgang, der ausgelöst wird, während ein anderer wartet, übernimmt den neueren Wert – so schreibt Speichern bei jeder Änderung den neuesten State, ohne die Warteschlange zu füllen.
useDraft.set('A');
const first = useDraft.save(); // writes "A"
useDraft.set('B');
const second = useDraft.save(); // waits in the queue
useDraft.set('C');
const third = useDraft.save(); // joins the waiting save
await Promise.all([first, second, third]); // ['A', 'C', 'C'] — two writesAusprobieren
Verlangsame den Speicher, lass Schreibvorgänge scheitern oder entferne den Speicher ganz.
Beispiel wird vorbereitet…
Wenn das Laden fehlschlägt
restateManager.ready wird mit BULK_OPERATION_FAILED abgelehnt und listet jeden fehlgeschlagenen Store auf. Bis dieser Datensatz geladen ist, ersetzen autoSave und saveAll ihn nicht und melden LOAD_FAILED.
Versuch es mit initialize() erneut, um deine Änderungen zu behalten und zu speichern, ruf restore() auf, um sie zu verwerfen, oder save(), um den Datensatz bewusst zu überschreiben.
try {
await restateManager.ready;
} catch (error) {
// BULK_OPERATION_FAILED: one entry per store that could not load.
for (const { store, error: cause } of error.failures) {
console.error(store.key, cause.code);
}
}Speichern und schließen
Ein vor dem Unmount angeforderter Speichervorgang wird trotzdem fertig, ein „Speichern und schließen“-Handler muss also nicht warten.
function Document({ onClose }) {
const useDraft = useRestateScope((scope) => persistedRestate('', { scope, key: 'draft' }));
const saveAndClose = () => {
useDraft.save(); // finishes even after this component unmounts
onClose();
};
// …
}Gespeicherte Daten validieren und migrieren
version, migrate und validate schützen dich vor alten oder beschädigten Datensätzen. validate läuft vor dem Speichern sowie nach dem Wiederherstellen oder Migrieren.
import { persistedRestate } from '@kkwaenggwari/restate';
const useSettings = persistedRestate(
{ theme: 'system' },
{
key: 'settings',
version: 2,
migrate(value, from, to) {
if (from === 1 && to === 2 && typeof value?.darkMode === 'boolean') {
return { theme: value.darkMode ? 'dark' : 'light' };
}
throw new Error('Unsupported stored version');
},
validate: (value) => ['system', 'light', 'dark'].includes(value?.theme),
},
);Eigenen Speicher mitbringen
Jedes Objekt mit getItem, setItem und removeItem funktioniert. Methoden können Werte oder Promises zurückgeben; isAvailable ist optional.
import { persistedRestate } from '@kkwaenggwari/restate';
const sessionStorageAdapter = {
isAvailable: () => typeof sessionStorage !== 'undefined',
getItem: (key) => sessionStorage.getItem(key),
setItem: (key, value) => sessionStorage.setItem(key, value),
removeItem: (key) => sessionStorage.removeItem(key),
};
export const useFilters = persistedRestate(
{ query: '' },
{
key: 'filters',
storage: sessionStorageAdapter,
},
);Limits und Timeouts
Leg fest, wie lange eine Operation laufen darf, wie viele warten dürfen und wie groß ein Wert sein darf.
persistedRestate(value, {
key: 'draft',
operationTimeoutMs: 10_000, // default 30000
maxPendingOperations: 64, // default 256
maxStorageCharacters: 1_000_000,
});Fehlercodes
Von restate erzeugte Fehler haben den name RestateError, einen code und bei gespeicherten Stores einen key. Speicheradapter und deine Callbacks können mit eigenen Fehlern ablehnen.
| Code | Bedeutung |
|---|---|
BULK_OPERATION_FAILED | Ein Sammelaufruf wie restateManager.ready oder saveAll hatte Fehler; siehe error.failures. |
INDEXEDDB_ABORTED | Eine IndexedDB-Transaktion wurde abgebrochen. |
INDEXEDDB_BLOCKED | Das Öffnen der Datenbank wurde durch eine Verbindung in einem anderen Tab blockiert. |
INDEXEDDB_CONNECTION_CLOSING | Die Datenbankverbindung wurde gerade geschlossen, als die Anfrage begann. |
INDEXEDDB_OPEN_FAILED | Die Datenbank konnte nicht geöffnet werden. |
INDEXEDDB_REQUEST_FAILED | Eine IndexedDB-Anfrage ist fehlgeschlagen. |
INDEXEDDB_STORE_MISSING | Der Object Store existiert in einer bereits erstellten Datenbank nicht. |
INVALID_STORAGE_RECORD | Ein gespeicherter Datensatz ist kein gültiger restate-Datensatz. |
INVALID_STORED_VALUE | Ein Wert hat validate nicht bestanden. |
LIFECYCLE_LIMIT | Ein updater hat sich immer wieder gestartet und gestoppt. |
LOAD_FAILED | Ein Datensatz konnte nicht geladen werden, daher hat ein automatischer oder Sammel-Speichervorgang ihn nicht ersetzt. |
MMKV_UNAVAILABLE | react-native-mmkv konnte nicht geladen werden. |
MULTIPLE_ERRORS | Mehrere Callbacks sind in einer Operation fehlgeschlagen; siehe error.errors. |
NOTIFICATION_LIMIT | Beobachter haben in einer Schleife immer weitere Änderungen eingeplant. |
OBSERVER_ERROR | Ein Listener oder ein Lifecycle-Callback hat einen Fehler geworfen. |
OPERATION_ABORTED | Eine Speicheroperation wurde abgebrochen. |
QUEUE_FULL | Es warteten mehr Operationen, als maxPendingOperations erlaubt. |
REENTRANT_SETTER | Ein State-updater hat versucht, während seiner Ausführung denselben Store zu ändern. |
SCOPE_DESTROYED | Ein zerstörter Scope wurde zum Erstellen von Stores verwendet. |
SEQUENCE_EXHAUSTED | Einer internen Sequenz sind die Kennungen ausgegangen. |
STORAGE_BLOCKED | Ein früherer Adapteraufruf ist nach einem Timeout oder Abbruch noch nicht abgeschlossen. |
STORAGE_TIMEOUT | Eine Operation hat länger als operationTimeoutMs gedauert. |
STORAGE_UNAVAILABLE | Speicher kann hier nicht genutzt werden; der Store arbeitet im Arbeitsspeicher weiter. |
STORAGE_VALUE_TOO_LARGE | Der kodierte Wert ist länger als maxStorageCharacters. |
STORAGE_VERSION_MISMATCH | Ein Datensatz hat eine andere Version, und keine migrate-Funktion behandelt sie. |
STORE_DESTROYED | Ein zerstörter Store wurde abonniert oder sollte Speicher nutzen. |