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 SeiteDie GarantienGeordnete SpeichervorgängeAusprobierenWenn das Laden fehlschlägtSpeichern und schließenKein Speicher verfügbarGespeicherte Daten validieren und migrierenEigenen Speicher mitbringenLimits und TimeoutsFehlercodes

Die Garantien

Dieses Verhalten ist Teil des 1.0-Vertrags und durch die Tests des Pakets abgedeckt.

SituationWas restate tut
Mehrere Speichervorgänge hintereinanderFührt sie pro Store der Reihe nach aus; ein in der Warteschlange wartender Speichervorgang schreibt den neuesten Wert.
Ein Datensatz konnte nicht geladen werdenautoSave und Sammel-Speichervorgänge überspringen ihn mit LOAD_FAILED; nur ein explizites save() ersetzt ihn.
Komponente wird während eines Speichervorgangs unmountetDer angeforderte Speichervorgang wird fertig; spätere Schreibvorgänge in den zerstörten Store werden ignoriert.
Speicher ist nicht verfügbarDer Store arbeitet im Arbeitsspeicher, status().available ist false, Speichervorgänge werden abgelehnt.
Ein Adapter hängtDie Operation läuft nach operationTimeoutMs ab, und spätere Arbeit wartet, bis der Adapter fertig ist.
Zu viel ausstehende ArbeitNeue 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.

JavaScript / JSX
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 writes

Ausprobieren

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.

JavaScript / JSX
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.

JavaScript / JSX
function Document({ onClose }) {
  const useDraft = useRestateScope((scope) => persistedRestate('', { scope, key: 'draft' }));

  const saveAndClose = () => {
    useDraft.save(); // finishes even after this component unmounts
    onClose();
  };
  // …
}

Kein Speicher verfügbar

Server-Rendering und blockierter Browserspeicher sind beim Start keine Fehler. Prüfe available, um Nutzern zu sagen, dass Änderungen nur im Arbeitsspeicher bleiben.

JavaScript / JSX
const { available } = useDraft.status();

if (!available) {
  // Server rendering or blocked browser storage: the store works in memory
  // and save() rejects with STORAGE_UNAVAILABLE.
  showNotice('Changes are kept until you close this tab.');
}

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.

JavaScript / JSX
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.

JavaScript / JSX
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.

JavaScript / JSX
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.

CodeBedeutung
BULK_OPERATION_FAILEDEin Sammelaufruf wie restateManager.ready oder saveAll hatte Fehler; siehe error.failures.
INDEXEDDB_ABORTEDEine IndexedDB-Transaktion wurde abgebrochen.
INDEXEDDB_BLOCKEDDas Öffnen der Datenbank wurde durch eine Verbindung in einem anderen Tab blockiert.
INDEXEDDB_CONNECTION_CLOSINGDie Datenbankverbindung wurde gerade geschlossen, als die Anfrage begann.
INDEXEDDB_OPEN_FAILEDDie Datenbank konnte nicht geöffnet werden.
INDEXEDDB_REQUEST_FAILEDEine IndexedDB-Anfrage ist fehlgeschlagen.
INDEXEDDB_STORE_MISSINGDer Object Store existiert in einer bereits erstellten Datenbank nicht.
INVALID_STORAGE_RECORDEin gespeicherter Datensatz ist kein gültiger restate-Datensatz.
INVALID_STORED_VALUEEin Wert hat validate nicht bestanden.
LIFECYCLE_LIMITEin updater hat sich immer wieder gestartet und gestoppt.
LOAD_FAILEDEin Datensatz konnte nicht geladen werden, daher hat ein automatischer oder Sammel-Speichervorgang ihn nicht ersetzt.
MMKV_UNAVAILABLEreact-native-mmkv konnte nicht geladen werden.
MULTIPLE_ERRORSMehrere Callbacks sind in einer Operation fehlgeschlagen; siehe error.errors.
NOTIFICATION_LIMITBeobachter haben in einer Schleife immer weitere Änderungen eingeplant.
OBSERVER_ERROREin Listener oder ein Lifecycle-Callback hat einen Fehler geworfen.
OPERATION_ABORTEDEine Speicheroperation wurde abgebrochen.
QUEUE_FULLEs warteten mehr Operationen, als maxPendingOperations erlaubt.
REENTRANT_SETTEREin State-updater hat versucht, während seiner Ausführung denselben Store zu ändern.
SCOPE_DESTROYEDEin zerstörter Scope wurde zum Erstellen von Stores verwendet.
SEQUENCE_EXHAUSTEDEiner internen Sequenz sind die Kennungen ausgegangen.
STORAGE_BLOCKEDEin früherer Adapteraufruf ist nach einem Timeout oder Abbruch noch nicht abgeschlossen.
STORAGE_TIMEOUTEine Operation hat länger als operationTimeoutMs gedauert.
STORAGE_UNAVAILABLESpeicher kann hier nicht genutzt werden; der Store arbeitet im Arbeitsspeicher weiter.
STORAGE_VALUE_TOO_LARGEDer kodierte Wert ist länger als maxStorageCharacters.
STORAGE_VERSION_MISMATCHEin Datensatz hat eine andere Version, und keine migrate-Funktion behandelt sie.
STORE_DESTROYEDEin zerstörter Store wurde abonniert oder sollte Speicher nutzen.

Doku durchsuchen

Durchsucht Titel, Beschreibungen und Text aller Guides.