Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

同期エラーの処理 - Swift SDK

項目一覧

  • 同期エラーの処理
  • クライアント リセット
  • 自動クライアントリセットと手動クライアントリセット
  • クライアントリセットモードの指定
  • スキーマの変更の処理
  • 同期されていない変更の回復
  • 同期されていない変更の破棄
  • 手動クライアントリセットモード
  • 手動クライアントリセットフォールバック
  • クライアント リセット処理をテストします

Device Sync を使用するアプリケーションを開発する際には、エラー ハンドラーを設定する必要があります。 このエラー ハンドラーは、失敗した同期関連の API 呼び出しを検出し、応答します。

Tip

一般的な Device Sync エラーのリストとその処理方法については、App Services Device Sync ドキュメントの「 Sync エラー 」を参照してください。

RMSyncManager シングルオンにエラーハンドラーを設定します。 エラーが発生すると、Swift SDK は、エラー オブジェクトとエラーが発生したRMSyncSessionを使用してエラー ハンドラーを呼び出します。

注意

Realm は、ドメインが RMSyncErrorDomain である DNSError オブジェクトを通じて同期エラーを表します。エラー コードの詳細については、 RMSyncErrorRMSyncAuthError の定義を確認してください。

RLMApp *app = [RLMApp appWithId:YOUR_APP_ID];
// Access the sync manager for the app
RLMSyncManager *syncManager = [app syncManager];
syncManager.errorHandler = ^(NSError *error, RLMSyncSession *session) {
// handle error
};

Sync Manager のみにエラー ハンドラーを設定します。 Sync Manager のみにエラー ハンドラーを設定します。 エラーが発生すると、Swift SDK は、エラー オブジェクトとエラーが発生したSyncSessionを使用してエラー ハンドラーを呼び出します。

let app = App(id: YOUR_APP_SERVICES_APP_ID)
app.syncManager.errorHandler = { error, session in
// handle error
}

Tip

以下も参照してください。

クライアント ログ レベルの設定、またはロガーのカスタマイズの詳細については、「クライアント ログ レベルの設定 - Swift SDK 」を参照してください。

Device Syncを使用する場合、クライアントリセットは、サーバー上の特定の同期された Realm がクライアント Realm と同期できなくなった場合にクライアントアプリが実行する必要があるエラー回復タスクです。 この場合、同期機能を復元するには、クライアントが Realm をサーバーと一致する状態にリセットする必要があります。

この状況が発生すると、クライアント上の同期できない Realm には、サーバーにまだ同期されていないデータが含まれている可能性があります。 Realm SDK は、クライアントのリセット プロセス中にそのデータの回復または破棄を試行できます。

クライアント リセットが発生する可能性のある原因について詳しくGo は、Atlas App Services ドキュメントの「 クライアントのリセット 」に してください。

Realm SDK は、ほとんどのクライアント リセット エラーを自動的に処理するクライアント リセット モードを提供します。 自動クライアント リセット モードでは、Realm を閉じたり通知が欠落したりすることなく、ローカル Realm ファイルが同期可能な状態に復元されます。

.manualを除くすべてのクライアント リセット モードで、自動クライアント リセットが実行されます。 モード間の違いは、バックエンドにまだ同期されていないデバイス上の変更をどのように処理するかに基づいています。

ほとんどのクライアント リセット シナリオを自動的に処理するには、 .recoverUnsyncedChangesを選択します。 これは、クライアントがリセットしたときに同期されていない変更を回復しようとします。

場合によっては、クライアント リセット ハンドラーを手動で設定する必要があるか、または設定する必要がある場合があります。 自動的には処理できない特定のクライアント リセット ロジックがアプリで必要とされる場合は、これを実行することをお勧めします。

バージョン10.32.0での変更: クライアントリカバリを追加し、破棄ローカルの名前を変更しました

Swift SDK には、 SyncConfigurationでクライアント リセット モードを指定するオプションが用意されています。 これは.clientResetMode プロパティ。

// Specify the clientResetMode when you create the SyncConfiguration.
// If you do not specify, this defaults to `.recoverUnsyncedChanges` mode.
var configuration = user.flexibleSyncConfiguration(clientResetMode: .recoverUnsyncedChanges())

このプロパティは、さまざまなクライアント リセット モードを表す列挙型を受け取ります。

  • .recoverUnsyncedChanges

  • .recoverOrDiscardUnsyncedChanges

  • .discardUnsyncedChanges

  • .manual

構成で.clientResetModeを指定しない場合、クライアント リセット モードはデフォルトで.recoverUnsyncedChangesになります。

beforeafter自動クライアント リセット プロセス中に実行する ブロックと ブロックを指定できます。これを使用して、アプリケーションにとって重要なリカバリ ロジックを実行することがあります。

// A block called after a client reset error is detected, but before the
// client recovery process is executed.
// This block could be used for any custom logic, reporting, debugging etc.
// This is one example, but your usage may vary.
let beforeClientResetBlock: (Realm) -> Void = { before in
var recoveryConfig = Realm.Configuration()
recoveryConfig.fileURL = myRecoveryPath
do {
try before.writeCopy(configuration: recoveryConfig)
// The copied realm could be used later for recovery, debugging, reporting, etc.
} catch {
// handle error
}
}
// A block called after the client recovery process has executed.
// This block could be used for custom recovery, reporting, debugging etc.
// This is one example, but your usage may vary.
let afterClientResetBlock: (Realm, Realm) -> Void = { before, after in
// let res = after.objects(myClass.self)
// if (res.filter("primaryKey == %@", object.primaryKey).first != nil) {
// // ...custom recovery logic...
// } else {
// // ...custom recovery logic...
// }
// }
}
do {
let app = App(id: YOUR_APP_SERVICES_APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
var configuration = user.flexibleSyncConfiguration(clientResetMode:
.recoverOrDiscardUnsyncedChanges(
beforeReset: beforeClientResetBlock,
afterReset: afterClientResetBlock))
} catch {
print("Error logging in user: \(error.localizedDescription)")
}

アプリに特定のクライアント回復が必要な場合は、 .manualクライアント リセット モードを指定し、手動のクライアント リセット ハンドラーを設定できます。 クライアント リセット中にアプリで実行する必要がある特定のカスタム ロジックがある場合、またはクライアント回復ルールがアプリで機能しない場合は、この操作を行うことがあります。

注意

アプリで Swift SDK バージョン 10.24.2 またはそれ以前のバージョンが使用されている場合、 .clientResetModeSyncConfigurationで使用できないプロパティではありません。

クライアントリカバリは、 Device Sync を構成するとデフォルトで有効になる機能です。 クライアントリカバリが有効になっている場合、Realm はほとんどの場合にクライアントのリセットプロセスを自動的に管理できます。 スキーマを変更する際:

  • クライアントは、スキーマ変更がない場合、またはスキーマの重大でない変更がない場合に、同期されていない変更を回復できます。

  • スキーマの重大な変更を行うと、自動クライアント リセット モードは手動エラー ハンドラーにフォールバックします。 この場合は、手動のクライアント リセット エラー ハンドラーを設定できます。 アプリがスキーマの重大な変更を行った場合は、自動クライアント回復は実行できません。

スキーマの重大な変更と重大でない変更の詳細については、「 重大な変更と重大でない変更のクイック リファレンス 」を参照してください。

バージョン10.32.0の新機能

クライアントのリセット中に、クライアント アプリケーションは、バックエンドにまだ同期されていないローカル Realm 内のデータの回復を試行できます。 同期されていない変更を回復する には、 App Services App でデフォルトで有効になっている クライアントリカバリ を有効にする必要があります。

まだ同期されていない変更をアプリで回復するには、 SyncConfiguration.clientResetModeを次のいずれかに設定します。

  • .recoverUnsyncedChanges: このモードを選択すると、クライアントは同期されていない変更の回復を試みます。 同期されていない変更を破棄するために失敗したくない場合は、このモードを選択します。

  • .recoverOrDiscardUnsyncedChanges: クライアントは最初に、まだ同期されていない変更の回復を試みます。 クライアントが同期されていないデータを復元できない場合、同期されていない変更を破棄しますが、クライアントのリセットの自動実行は続行されます。 同期されていない変更を破棄するためにバックアップする自動クライアントリカバリを有効にする場合は、このモードを選択します。

// Specify the clientResetMode when you create the SyncConfiguration.
// If you do not specify, this defaults to `.recoverUnsyncedChanges` mode.
var configuration = user.flexibleSyncConfiguration(clientResetMode: .recoverUnsyncedChanges())

スキーマの重大な変更が発生した場合や、Device Sync 構成でクライアントリカバリが無効になっている場合など、同期されていない変更モードでクライアントのリセット操作が完了しない場合があります。 この場合を処理するために、アプリは手動のクライアントリセットフォールバックを実装できます。

クライアントリカバリが有効になっている場合、バックエンドとクライアントの両方が同じオブジェクトに変更を加えた場合に競合が解決される方法など、オブジェクトの統合方法がこれらのルールによって決まります。

  • クライアントがリセットされる前に同期されなかったローカルで作成されたオブジェクトが同期されます。

  • オブジェクトがサーバー上で削除されたが、復元されたクライアントで変更された場合は、削除が優先され、クライアントは更新を破棄します。

  • リカバリ クライアントでオブジェクトが削除されたが、サーバーでは削除された場合、クライアントはサーバーの削除指示を適用します。

  • 同じフィールドへの更新が競合する場合は、クライアント更新が適用されます。

バージョン 10.32.0 での変更: .discardLocal .discardUnsyncedchanges に変更

同期されていない変更を破棄するクライアント リセット モードでは、最後の同期が成功した以降に行われたすべてのローカルの同期されていない変更が永続的に削除されます。 Device Syncクライアント回復ルールと整合性のないクライアント回復ロジックがアプリで必要な場合、または同期されていないデータを回復したくない場合は、このモードを使用できます。

バックエンドにまだ同期されていないローカル データをアプリケーションが失うことができない場合は、同期されていない変更モードを使用しないでください。

同期されていない変更を破棄する自動クライアントリセットを実行するには、 SyncConfiguration.clientResetMode.discardUnsyncedChangesに設定します。

do {
let app = App(id: APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
var config = user.flexibleSyncConfiguration(clientResetMode: .discardUnsyncedChanges())
} catch {
print("Error logging in user: \(error.localizedDescription)")
}

注意

リカバリを使用して破棄

同期されていない変更の復元を試み、復元できない変更を破棄する場合は、同期されていない変更の復元に関する.recoverOrDiscardUnsyncedChangesのドキュメントを参照してください

スキーマの重大な変更が発生した場合など、非同期変更の破棄モードではクライアントのリセット操作が完了しない場合があります。 この場合を処理するために、アプリは手動のクライアントリセットフォールバックを実装できます。

.clientResetMode.manualを指定する場合は、手動クライアント リセット ハンドラーを実装する必要があります。

.manualモードでは、独自のクライアント リセット ハンドラーを定義します。 ハンドラーはErrorReportingBlockを指定できます。 可能な場合は自動クライアント回復モードを使用し、自動回復ロジックがアプリに適していない場合にのみ.manualモードを選択することをお勧めします。

do {
let app = App(id: APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
var config = user.flexibleSyncConfiguration(clientResetMode: .manual())
} catch {
print("Error logging in user: \(error.localizedDescription)")
}

Tip

古いバージョンの SDK を使用しており、手動クライアント リセットで変更を手動で回復する方法の例が必要な場合は 、 Githubでこの例を確認してください。

スキーマの重大な変更が発生した場合など、クライアントのリセット操作が自動的に完了しない場合、クライアントのリセットプロセスは手動のエラーハンドラーに降格します。 これは、次のいずれかの自動クライアント リセット モードで発生する可能性があります。

  • .recoverUnsyncedChanges

  • .recoverOrDiscardUnsyncedChanges

  • .discardUnsyncedChanges

このフォールバック ケース用のエラー ハンドラーは、 RMApp RMSyncManager インスタンスを介して設定できます。アプリをアップデートしたり、その他のアクションを実行するようユーザーに提案する場合、致命的なエラー回復ツールとして手動ハンドラーを使うことをお勧めします。

RLMApp *app = [RLMApp appWithId:YOUR_APP_ID];
[[app syncManager] setErrorHandler:^(NSError *error, RLMSyncSession *session) {
if (error.code == RLMSyncErrorClientResetError) {
// TODO: Invalidate all open realm instances
// TODO: Restore the local changes backed up at [error rlmSync_clientResetBackedUpRealmPath]
[RLMSyncSession immediatelyHandleError:[error rlmSync_errorActionToken] syncManager:[app syncManager]];
return;
}
// Handle other errors...
}];

SyncManagerを使用して、このフォールバックケースのエラー ハンドラーを設定できます。 アプリをアップデートしたり、その他のアクションを実行するようユーザーに提案する場合、致命的なエラー回復ツールとして手動ハンドラーを使うことをお勧めします。

func handleClientReset() {
// Report the client reset error to the user, or do some custom logic.
}
do {
let app = App(id: APP_ID)
let user = try await app.login(credentials: Credentials.anonymous)
var config = user.flexibleSyncConfiguration(clientResetMode: .recoverOrDiscardUnsyncedChanges())
// If client recovery fails,
app.syncManager.errorHandler = { error, session in
guard let syncError = error as? SyncError else {
fatalError("Unexpected error type passed to sync error handler! \(error)")
}
switch syncError.code {
case .clientResetError:
if let (path, clientResetToken) = syncError.clientResetInfo() {
handleClientReset()
SyncSession.immediatelyHandleError(clientResetToken, syncManager: app.syncManager)
}
default:
// Handle other errors...
()
}
}
} catch {
print("Error: \(error.localizedDescription)")
}

Device Sync を終了して再度有効にすることで、アプリケーションのクライアント リセット処理を手動でテストできます。

同期を終了して再度有効にすると、以前に同期に接続したことのあるクライアントは、クライアント リセットを実行するまで接続できなくなります。 同期を終了すると、クライアントが同期できるようにするメタデータがサーバーから削除されます。 クライアントは、サーバーから Realm の新しいコピーをダウンロードする必要があります。 サーバーはこれらのクライアントにクライアント リセット エラーを送信します。 したがって、同期を終了すると、クライアントのリセット条件がtriggerされます。

クライアント リセット処理をテストするには:

  1. クライアント アプリケーションからデータを書き込み、同期されるまで待ちます。

  2. Device Sync を終了して再度有効にします。

  3. クライアント アプリを再度実行します。 アプリは、サーバーに接続しようとすると、クライアント リセット エラーを取得します。

警告

クライアント アプリケーションでクライアント リセット処理を反復処理している間に、同期を繰り返し終了して再度有効にする必要がある場合があります。 同期を終了して再度有効にすると、既存のすべてのクライアントは、クライアントのリセットが完了するまで同期できなくなります。 本番環境でこれを回避するには、開発環境でクライアントのリセット処理をテストします。

戻る

同期された Realm への書き込み