restate / v1.0.0

안정성 설계

저장소가 느리거나 실패하거나 없을 때 restate가 보장하는 것, 그리고 보고하는 오류를 읽는 방법.

이 페이지에서보장 목록순서가 보장되는 저장직접 해 보기불러오기가 실패했을 때저장하고 닫기저장소를 쓸 수 없을 때저장 데이터 검증과 마이그레이션직접 만든 저장소한도와 시간 제한오류 코드

보장 목록

아래 동작은 1.0 계약의 일부이며 패키지 테스트로 확인합니다.

상황restate의 동작
연달아 여러 번 저장스토어마다 순서대로 실행하고, 큐에서 기다리는 저장은 가장 새 값을 씁니다.
기록을 불러오지 못함autoSave와 일괄 저장은 LOAD_FAILED로 건너뛰고, 명시적인 save()만 기록을 바꿉니다.
저장 중 컴포넌트 언마운트요청한 저장은 끝까지 진행하고, 파괴된 스토어의 이후 쓰기는 무시합니다.
저장소를 쓸 수 없음스토어는 메모리로 동작하고 status().available은 false, 저장은 거부됩니다.
어댑터가 멈춤operationTimeoutMs 뒤 작업이 시간 초과되고, 이후 작업은 어댑터가 정리될 때까지 기다립니다.
대기 작업이 너무 많음끝없이 쌓는 대신 새 작업을 QUEUE_FULL로 거부합니다.

순서가 보장되는 저장

한 스토어의 작업은 겹치지 않습니다. 다른 저장이 기다리는 동안 부른 저장은 더 새로운 값을 받으므로, 변경마다 저장해도 큐를 채우지 않고 최신 상태를 씁니다.

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

직접 해 보기

저장소를 느리게 하고, 쓰기를 실패시키고, 저장소를 아예 없애 보세요.

예제를 준비하는 중…

불러오기가 실패했을 때

restateManager.ready는 BULK_OPERATION_FAILED로 거부되며 실패한 스토어를 하나씩 알려 줍니다. 그 기록을 불러올 때까지 autoSave와 saveAll은 기록을 바꾸지 않고 LOAD_FAILED를 알립니다.

편집을 지키며 저장하려면 initialize()를 다시 시도하고, 편집을 버리려면 restore()를, 의도적으로 기록을 덮어쓰려면 save()를 부르세요.

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);
  }
}

저장하고 닫기

언마운트 전에 요청한 저장은 끝까지 진행되므로, 저장하고 닫기 핸들러는 저장을 기다리지 않아도 됩니다.

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

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

저장소를 쓸 수 없을 때

서버 렌더링과 막힌 브라우저 저장소는 시작 오류가 아닙니다. available을 확인해 변경이 메모리에만 남는다고 알려 주세요.

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.');
}

저장 데이터 검증과 마이그레이션

version, migrate, validate가 오래되거나 손상된 기록으로부터 앱을 지킵니다. validate는 저장 전과, 복원이나 마이그레이션 뒤에 실행됩니다.

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),
  },
);

직접 만든 저장소

getItem, setItem, removeItem을 가진 객체라면 무엇이든 됩니다. 메서드는 값이나 Promise를 반환할 수 있고 isAvailable은 선택입니다.

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,
  },
);

한도와 시간 제한

작업 하나가 실행될 수 있는 시간, 기다릴 수 있는 작업 수, 값의 최대 크기를 조절합니다.

JavaScript / JSX
persistedRestate(value, {
  key: 'draft',
  operationTimeoutMs: 10_000, // default 30000
  maxPendingOperations: 64, // default 256
  maxStorageCharacters: 1_000_000,
});

오류 코드

restate가 만든 오류는 이름이 RestateError이고 code를, 저장 스토어라면 key도 가집니다. 저장소 어댑터나 직접 작성한 콜백은 자기 오류로 거부할 수 있습니다.

코드의미
BULK_OPERATION_FAILEDrestateManager.ready나 saveAll 같은 일괄 호출에 실패가 있습니다. error.failures를 확인하세요.
INDEXEDDB_ABORTEDIndexedDB 트랜잭션이 중단되었습니다.
INDEXEDDB_BLOCKED다른 탭의 연결 때문에 데이터베이스를 열지 못했습니다.
INDEXEDDB_CONNECTION_CLOSING요청이 시작될 때 데이터베이스 연결이 닫히는 중이었습니다.
INDEXEDDB_OPEN_FAILED데이터베이스를 열 수 없습니다.
INDEXEDDB_REQUEST_FAILEDIndexedDB 요청이 실패했습니다.
INDEXEDDB_STORE_MISSING이미 만들어진 데이터베이스에 해당 object store가 없습니다.
INVALID_STORAGE_RECORD저장된 기록이 올바른 restate 기록이 아닙니다.
INVALID_STORED_VALUE값이 validate를 통과하지 못했습니다.
LIFECYCLE_LIMITupdater가 스스로 시작과 정지를 반복했습니다.
LOAD_FAILED기록을 불러오지 못해 자동 저장이나 일괄 저장이 그 기록을 바꾸지 않았습니다.
MMKV_UNAVAILABLEreact-native-mmkv를 불러오지 못했습니다.
MULTIPLE_ERRORS한 작업에서 여러 콜백이 실패했습니다. error.errors를 확인하세요.
NOTIFICATION_LIMIT구독자가 변경을 반복해서 예약했습니다.
OBSERVER_ERROR리스너나 수명 주기 콜백이 오류를 던졌습니다.
OPERATION_ABORTED저장소 작업이 취소되었습니다.
QUEUE_FULL기다리는 작업이 maxPendingOperations보다 많습니다.
REENTRANT_SETTER상태 updater가 실행 중에 같은 스토어를 바꾸려 했습니다.
SCOPE_DESTROYED파괴된 scope로 스토어를 만들려 했습니다.
SEQUENCE_EXHAUSTED내부 순번이 더 이상 식별자를 만들 수 없습니다.
STORAGE_BLOCKED시간 초과나 중단 뒤에도 이전 어댑터 호출이 끝나지 않았습니다.
STORAGE_TIMEOUT작업이 operationTimeoutMs보다 오래 걸렸습니다.
STORAGE_UNAVAILABLE여기서는 저장소를 쓸 수 없습니다. 스토어는 메모리로 계속 동작합니다.
STORAGE_VALUE_TOO_LARGE인코딩한 값이 maxStorageCharacters보다 깁니다.
STORAGE_VERSION_MISMATCH기록의 버전이 다르고 이를 처리할 migrate 함수가 없습니다.
STORE_DESTROYED파괴된 스토어를 구독하거나 저장소 작업에 사용했습니다.

문서 검색

모든 가이드의 제목·설명·본문을 검색합니다.