문서 메뉴

문서 홈애플리케이션 개발Atlas Device SDK

수동 클라이언트 재설정 데이터 복구 - React Native SDK

이 페이지의 내용

  • 객체 전략별 변경 사항 추적
  • 예제
  • 스키마에 마지막 업데이트 시간 포함
  • 수동 클라이언트 재설정을 사용하도록 Realm 구성
  • 별도의 Realm에서 동기화 추적
  • 클라이언트 재설정을 처리하는 콜백 만들기
  • 대체 전략

이 페이지에서는 수동 복구 클라이언트 재설정 모드를 사용하여 클라이언트 재설정 후 동기화되지 않은 영역 데이터를 수동으로 복구하는 방법에 대해 설명합니다.

수동 복구에는 상당한 양의 코드, 스키마 양보 및 사용자 지정 충돌 해결 로직이 필요합니다. 동기화되지 않은 데이터를 잃을 수 없고 다른 자동 클라이언트 재설정 방법이 사용 사례에 맞지 않는 경우에만 동기화되지 않은 realm 데이터의 수동 복구를 수행해야 합니다.

사용 가능한 다른 클라이언트 재설정 모드에 대한 자세한 내용은 클라이언트 Realm 재설정을 참조하세요.

수동 복구의 세부 사항은 애플리케이션과 스키마에 따라 크게 달라집니다. 그러나 수동 복구에 도움이 될 수 있는 몇 가지 기술이 있습니다. 객체 전략별 변경 사항 추적 섹션 에서는 클라이언트 재설정 중에 동기화되지 않은 변경 사항을 복구하는 한 가지 방법을 보여 줍니다.

경고

프로덕션 환경에서 손상적인 스키마 변경 방지

손상적인 스키마 변경 후 동기화되지 않은 모든 데이터를 복구할 것으로 기대하지 마세요. 사용자 데이터를 보존하는 가장 좋은 방법은 손상적인 스키마 변경을 전혀 수행하지 않는 것입니다.

중요

손상적인 스키마 변경에는 앱 스키마 업데이트가 필요합니다.

손상적인 스키마 변경 후 다음을 수행합니다:

  • 모든 클라이언트는 클라이언트 재설정을 수행해야 합니다.

  • 손상적인 스키마 변경의 영향을 받는 클라이언트 모델을 업데이트해야 합니다.

객체에 따른 클라이언트 재설정 데이터 복구의 변경 사항 추적을 사용하면 이미 Realm 파일에 기록되었지만 아직 백엔드에 동기화되지 않은 데이터를 복구할 수 있습니다.

이 전략에서는 각 Realm 객체 모델에 "마지막 업데이트 시간"을 추가하여 각 객체가 마지막으로 변경된 시간을 추적합니다. 영역이 언제 상태를 백엔드에 마지막으로 업로드했는지 확인하기 위해 관찰할 것입니다.

백엔드가 클라이언트 재설정을 호출하면 백엔드와의 마지막 동기화 이후 삭제, 생성 또는 업데이트된 객체를 찾습니다. 그런 다음 백업 영역에서 새 영역으로 해당 데이터를 복사합니다.

다음 단계는 높은 수준에서 프로세스를 구현하는 방법을 보여줍니다.

  1. 클라이언트 재설정 오류: 애플리케이션이 백엔드에서 클라이언트 재설정 오류 코드를 수신합니다.

  2. 전략 구현: SDK가 전략 구현을 호출합니다.

  3. 영역의 모든 인스턴스 닫기 : 클라이언트 재설정이 발생하는 영역의 열려 있는 모든 인스턴스를 닫습니다. 애플리케이션 아키텍처로 인해 이를 달성하기 어려운 경우(예: 앱이 애플리케이션 전체의 리스너에서 동시에 많은 Realm 인스턴스를 사용하는 경우) 애플리케이션을 다시 시작하는 것이 더 쉬울 수 있습니다. 프로그래밍 방식으로 또는 대화 상자에서 사용자에 대한 직접 요청을 통해 이 작업을 수행할 수 있습니다.

  4. 영역을 백업 파일로 이동: Realm.App.Sync.initiateClientReset() 정적 메서드를 호출합니다. 이 메서드는 클라이언트 영역 파일의 현재 복사본을 백업 파일로 이동합니다.

  5. 영역 의 새 인스턴스 열기 : 일반적인 동기화 구성을 사용하여 영역의 새 인스턴스를 엽니다. 애플리케이션에서 여러 영역을 사용하는 경우 백업 파일 이름에서 클라이언트 재설정이 발생한 영역을 식별할 수 있습니다.

  6. 백엔드에서 모든 Realm 데이터 다운로드 : 계속하기 전에 Realm의 전체 데이터 세트를 다운로드합니다. 이는 FlexibleSyncConfiguration 객체의 기본 동작입니다.

  7. 영역 백업 열기: SyncConfiguration.error 콜백 함수에 인수로 전달된 error.config 객체를 사용합니다.

  8. 동기화되지 않은 변경 사항 마이그레이션: 복구할 데이터에 대한 백업 영역을 쿼리합니다. 그에 따라 새 영역의 데이터를 삽입, 삭제 또는 업데이트합니다.

이 예에서는 객체별 변경 사항 추적 수동 클라이언트 재설정 데이터 복구 전략을 구현하는 방법을 보여 줍니다.

참고

이 예제의 제한 사항

  • 이 예제는 단일 Realm 객체 유형을 포함하는 단일 Realm이 있는 애플리케이션에만 적용됩니다. 각 추가 객체 유형에 대해 별도의 Realm에서 동기화 추적 섹션에 설명된 대로 다른 동기화 리스너를 추가해야 합니다.

  • 이 예제에서는 각 객체 가 마지막으로 업데이트된 시간을 추적합니다. 결과적으로 백업 영역의 마지막 동기화에 성공한 후 필드가 업데이트된 경우 복구 작업은 새 영역의 전체 객체를 덮어씁니다. 이로 인해 다른 클라이언트가 업데이트한 필드를 이 클라이언트의 이전 데이터로 덮어쓸 수 있습니다. Realm 객체에 중요한 데이터가 포함된 필드가 여러 개 포함된 경우 대신 각 필드 의 마지막 업데이트 시간을 추적하고 각 필드를 개별적으로 복구하는 것이 좋습니다.

데이터 복구를 통해 수동 클라이언트 재설정을 수행하는 다른 방법에 대한 자세한 내용은 대체 전략 섹션을 참조하세요.

1

Realm 객체 스키마에 새 속성을 추가하여 마지막으로 업데이트된 시간을 추적합니다. 스키마로 Realm 객체를 만들거나 업데이트할 때마다 업데이트 시간과 함께 타임스탬프를 포함하세요.

일반적으로 Realm 객체가 마지막으로 수정된 시점을 감지할 수 있는 방법은 없습니다. 이로 인해 백엔드에 동기화된 변경 사항을 확인하기가 어렵습니다. Realm 객체 모델에 타임스탬프 lastUpdated 을 추가하고 변경이 발생할 때마다 해당 타임스탬프를 현재 시간으로 업데이트하면 객체가 변경된 시점을 추적할 수 있습니다.

const DogSchema = {
name: "Dog",
properties: {
name: "string",
age: "int?",
lastUpdated: "int",
},
};
2

Realm의 FlexibleSyncConfiguration 에서 clientReset 필드를 수동 모드로 설정하고 error 콜백 함수를 포함합니다. 클라이언트 재설정을 처리하기 위한 콜백 생성 섹션에서 오류 콜백 함수를 정의합니다.

const config = {
schema: [DogSchema],
sync: {
user: app.currentUser,
partitionValue: "MyPartitionValue",
clientReset: {
mode: "manual",
},
error: handleSyncError, // callback function defined later
},
};
3

객체가 변경된 시점을 알고 있다는 것만으로는 클라이언트 재설정 중에 데이터를 복구하는 데 충분하지 않습니다. 또한 영역이 마지막으로 동기화를 성공적으로 완료한 시점을 알아야 합니다. 이 구현 예시에서는 변경 리스너와 쌍을 이루는 LastSynced 라는 별도의 영역에 있는 싱글톤 객체를 사용하여 영역의 동기화가 성공적으로 완료되는 시점을 기록합니다.

LastSynced Realm을 정의하여 영역이 동기화되는 가장 최근 시간을 추적합니다.

const LastSyncedSchema = {
name: "LastSynced",
properties: {
realmTracked: "string",
timestamp: "int?",
},
primaryKey: "realmTracked",
};
const lastSyncedConfig = { schema: [LastSyncedSchema] };
const lastSyncedRealm = await Realm.open(lastSyncedConfig);
lastSyncedRealm.write(() => {
lastSyncedRealm.create("LastSynced", {
realmTracked: "Dog",
});
});

변경 리스너를 등록하여 Dog collection의 변경 사항을 구독합니다. 동기화 세션이 연결되어 있고 모든 로컬 변경 사항이 서버와 동기화된 경우에만 LastSynced 객체를 업데이트합니다.

// Listens for changes to the Dogs collection
realm.objects("Dog").addListener(async () => {
// only update LastSynced if sync session is connected
// and all local changes are synced
if (realm.syncSession.isConnected()) {
await realm.syncSession.uploadAllLocalChanges();
lastSyncedRealm.write(() => {
lastSyncedRealm.create("LastSynced", {
realmTracked: "Dog",
timestamp: Date.now(),
});
});
}
});
4

이제 애플리케이션의 모든 객체에 대한 업데이트 시간과 애플리케이션이 마지막으로 동기화를 완료한 시간을 기록했으므로 수동 복구 프로세스를 구현할 차례입니다. 이 예제에서는 두 가지 주요 복구 작업을 처리합니다.

  • 백업 영역에서 동기화되지 않은 삽입 및 업데이트 복원

  • 백업 영역에서 이전에 삭제된 객체를 새 영역에서 삭제합니다.

아래 코드 샘플에서 이러한 작업의 구현을 따라갈 수 있습니다.

async function handleSyncError(_session, error) {
if (error.name === "ClientReset") {
const realmPath = realm.path; // realm.path will not be accessible after realm.close()
realm.close(); // you must close all realms before proceeding
// pass your realm app instance and realm path to initiateClientReset()
Realm.App.Sync.initiateClientReset(app, realmPath);
// Redownload the realm
realm = await Realm.open(config);
const oldRealm = await Realm.open(error.config);
const lastSyncedTime = lastSyncedRealm.objectForPrimaryKey(
"LastSynced",
"Dog"
).timestamp;
const unsyncedDogs = oldRealm
.objects("Dog")
.filtered(`lastUpdated > ${lastSyncedTime}`);
// add unsynced dogs to synced realm
realm.write(() => {
unsyncedDogs.forEach((dog) => {
realm.create("Dog", dog, "modified");
});
});
// delete dogs from synced realm that were deleted locally
const syncedDogs = realm
.objects("Dog")
.filtered(`lastUpdated <= ${lastSyncedTime}`);
realm.write(() => {
syncedDogs.forEach((dog) => {
if (!oldRealm.objectForPrimaryKey("Dog", dog._id)) {
realm.delete(dog);
}
});
});
// make sure everything syncs and close old realm
await realm.syncSession.uploadAllLocalChanges();
oldRealm.close();
} else {
console.log(`Received error ${error.message}`);
}
}

가능한 대체 구현은 다음과 같습니다.

  • 백업 상태로 전체 백엔드 덮어쓰기: "마지막 업데이트 시간" 또는 "마지막 동기화 시간" 없이 백업 영역의 모든 객체를 새 영역으로 업서트합니다. 이 접근 방식으로는 동기화되지 않은 삭제를 복구할 방법이 없습니다. 이 접근 방식은 마지막 동기화 이후 다른 클라이언트가 백엔드에 기록된 모든 데이터를 덮어씁니다. 각 영역에 한 명의 사용자만 쓰는 애플리케이션에 권장됩니다.

  • 필드별 변경 사항 추적: 모든 객체 의 '마지막 업데이트 시간'을 추적하는 대신 모든 필드 의 '마지막 업데이트 시간'을 추적합니다. 다른 클라이언트의 필드 쓰기를 이전 데이터로 덮어쓰지 않으려면 이 로직을 사용하여 필드를 개별적으로 업데이트합니다. 필드 수준에서 충돌을 해결해야 하는 객체당 필드가 많은 애플리케이션에 권장됩니다.

  • 객체와 별도로 업데이트 추적 : 각 객체의 스키마에서 '마지막 업데이트 시간'을 추적하는 대신 스키마에 Updates 라는 다른 모델을 만듭니다. Updates 제외) 객체의 필드가 업데이트될 때마다 기본 키, 필드 및 업데이트 시간을 기록합니다. 클라이언트를 재설정하는 동안 백업 Realm에서 해당 필드의 최신 값을 사용하여 "마지막 동기화 시간" 이후에 발생한 모든 Update 이벤트를 "다시 작성"합니다. 이 접근 방식은 오래된 데이터로 필드를 덮어쓰지 않고 새 영역에서 동기화되지 않은 모든 로컬 변경 사항을 복제해야 합니다. 그러나 애플리케이션이 자주 작성하는 경우 업데이트 collection을 저장하는 데 비용이 많이 들 수 있습니다. 객체 모델에 'lastUpdated' 필드를 추가하는 것이 바람직하지 않은 애플리케이션에 권장됩니다.

← 동기화 오류 처리 - React Native SDK