restate / v1.0.0
Fiabilité dès la conception
Ce que restate garantit quand le stockage est lent, échoue ou est absent, et comment lire les erreurs qu’il signale.
Sur cette page
Les garantiesEnregistrements ordonnésEssayerQuand le chargement échoueEnregistrer et fermerAucun stockage disponibleValider et migrer les données enregistréesUtiliser votre propre stockageLimites et délaisCodes d’erreurLes garanties
Ces comportements font partie du contrat de la 1.0 et sont couverts par les tests du paquet.
| Situation | Ce que fait restate |
|---|---|
Plusieurs enregistrements à la suite | Les exécute dans l’ordre pour chaque store ; un enregistrement en file d’attente écrit la valeur la plus récente. |
Un enregistrement n’a pas pu être chargé | autoSave et les enregistrements groupés l’ignorent avec LOAD_FAILED ; seul un save() explicite le remplace. |
Le composant est démonté pendant un enregistrement | L’enregistrement demandé se termine ; les écritures ultérieures dans le store détruit sont ignorées. |
Le stockage est indisponible | Le store fonctionne en mémoire, status().available vaut false, les enregistrements sont rejetés. |
Un adaptateur se bloque | L’opération expire après operationTimeoutMs et le travail suivant attend que l’adaptateur se termine. |
Trop de travail en attente | Les nouvelles opérations sont rejetées avec QUEUE_FULL au lieu de s’accumuler sans limite. |
Enregistrements ordonnés
Les opérations d’un même store ne se chevauchent jamais. Un enregistrement émis pendant qu’un autre attend prend la valeur la plus récente : enregistrer à chaque changement écrit le dernier état sans remplir la file.
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 writesEssayer
Ralentissez le stockage, faites échouer les écritures ou supprimez-le complètement.
Préparation de l’exemple…
Quand le chargement échoue
restateManager.ready est rejeté avec BULK_OPERATION_FAILED et liste chaque store en échec. Tant que cet enregistrement n’est pas chargé, autoSave et saveAll ne le remplacent pas et signalent LOAD_FAILED.
Relancez initialize() pour conserver vos modifications et les enregistrer, appelez restore() pour les abandonner, ou save() pour écraser l’enregistrement volontairement.
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);
}
}Enregistrer et fermer
Un enregistrement demandé avant le démontage se termine quand même : un gestionnaire « Enregistrer et fermer » n’a pas besoin d’attendre.
function Document({ onClose }) {
const useDraft = useRestateScope((scope) => persistedRestate('', { scope, key: 'draft' }));
const saveAndClose = () => {
useDraft.save(); // finishes even after this component unmounts
onClose();
};
// …
}Valider et migrer les données enregistrées
version, migrate et validate vous protègent des enregistrements anciens ou corrompus. validate s’exécute avant l’enregistrement et après la restauration ou la migration.
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),
},
);Utiliser votre propre stockage
N’importe quel objet doté de getItem, setItem et removeItem convient. Les méthodes peuvent renvoyer des valeurs ou des Promises ; isAvailable est facultatif.
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,
},
);Limites et délais
Réglez la durée maximale d’une opération, le nombre d’opérations en attente et la taille maximale d’une valeur.
persistedRestate(value, {
key: 'draft',
operationTimeoutMs: 10_000, // default 30000
maxPendingOperations: 64, // default 256
maxStorageCharacters: 1_000_000,
});Codes d’erreur
Les erreurs créées par restate ont le name RestateError, un code et, pour les stores enregistrés, key. Les adaptateurs de stockage et vos callbacks peuvent rejeter avec leurs propres erreurs.
| Code | Signification |
|---|---|
BULK_OPERATION_FAILED | Un appel groupé comme restateManager.ready ou saveAll a rencontré des échecs ; voir error.failures. |
INDEXEDDB_ABORTED | Une transaction IndexedDB a été annulée. |
INDEXEDDB_BLOCKED | L’ouverture de la base de données a été bloquée par une connexion dans un autre onglet. |
INDEXEDDB_CONNECTION_CLOSING | La connexion à la base de données se fermait au début de la requête. |
INDEXEDDB_OPEN_FAILED | Impossible d’ouvrir la base de données. |
INDEXEDDB_REQUEST_FAILED | Une requête IndexedDB a échoué. |
INDEXEDDB_STORE_MISSING | Le magasin d’objets n’existe pas dans une base déjà créée. |
INVALID_STORAGE_RECORD | Un enregistrement sauvegardé n’est pas un enregistrement restate valide. |
INVALID_STORED_VALUE | Une valeur n’a pas passé validate. |
LIFECYCLE_LIMIT | Un updater ne cessait de démarrer et de s’arrêter. |
LOAD_FAILED | Un enregistrement n’a pas pu être chargé, donc un enregistrement automatique ou groupé ne l’a pas remplacé. |
MMKV_UNAVAILABLE | Impossible de charger react-native-mmkv. |
MULTIPLE_ERRORS | Plusieurs callbacks ont échoué au cours d’une opération ; voir error.errors. |
NOTIFICATION_LIMIT | Des observateurs ont continué de programmer des changements en boucle. |
OBSERVER_ERROR | Un listener ou un callback de cycle de vie a levé une erreur. |
OPERATION_ABORTED | Une opération de stockage a été annulée. |
QUEUE_FULL | Plus d’opérations attendaient que ne l’autorise maxPendingOperations. |
REENTRANT_SETTER | Un updater d’état a tenté de modifier le même store pendant son exécution. |
SCOPE_DESTROYED | Un scope détruit a été utilisé pour créer des stores. |
SEQUENCE_EXHAUSTED | Une séquence interne n’a plus d’identifiants disponibles. |
STORAGE_BLOCKED | Un appel précédent à l’adaptateur ne s’est pas terminé après un délai dépassé ou une annulation. |
STORAGE_TIMEOUT | Une opération a duré plus longtemps que operationTimeoutMs. |
STORAGE_UNAVAILABLE | Le stockage n’est pas utilisable ici ; le store continue de fonctionner en mémoire. |
STORAGE_VALUE_TOO_LARGE | La valeur encodée dépasse maxStorageCharacters. |
STORAGE_VERSION_MISMATCH | Un enregistrement a une autre version et aucune fonction migrate ne le prend en charge. |
STORE_DESTROYED | On s’est abonné à un store détruit ou on lui a demandé d’utiliser le stockage. |