同期エラーの処理 - Kotlin SDK
項目一覧
Device Syncを使用するアプリケーションを開発する際には、エラー ハンドラーを設定する必要があります。 このエラー ハンドラーは、失敗した同期関連の API 呼び出しを検出し、応答します。
Tip
一般的な Device Sync エラーのリストとその処理方法については、App Services Device Sync ドキュメントの「同期エラー 」を参照してください。
同期エラーの処理
SyncConfiguration.errorHandlerを通じてエラー ハンドラーを設定します プロパティ(同期された Realm を作成するとき) エラーが発生すると、 Kotlin SDK は、エラー オブジェクトとエラーが発生したSyncSessionを使用してエラー ハンドラーを呼び出します。
エラーハンドラーを指定しない場合のデフォルトの動作は同期エラーをコンソールに出力します。
val syncErrorHandler = SyncSession.ErrorHandler { session, error -> Log.e("Error message" + error.message.toString()) } runBlocking { val user = app.login(credentials) val config = SyncConfiguration.Builder(user, setOf(Toad::class)) .initialSubscriptions { realm -> add(realm.query<Toad>(), "subscription name") } .errorHandler(syncErrorHandler) // Specify a sync error handler .build() // Proceed to open a realm... }
クライアント ログ レベルの設定やロガーのカスタマイズについて詳しくは、 「 クライアント ログ レベルの設定 - Kotlin SDK 」を参照してください。
同期の例外
SyncExceptionは、 AppExceptionのサブクラスです。 Device Sync が失敗すると SyncException
が発生します。
アプリの例外の詳細については、 「 アプリ エラーの処理 」を参照してください。
回復不能な同期エラー
Device Sync が致命的に失敗した場合、 UnrecoverableSyncExceptionが発生します。 これは通常、クライアントまたは接続されたアプリのバグを意味します。
回復不能な同期エラーが発生した場合は、エンドユーザーに問題を提示する必要があります。 問題が解決されるまで、Device Sync が機能しないことをユーザーに伝えてください。 バックエンド アプリのログを確認して、問題をできるだけ早く修正できるように、自分にアラートを送信することをお勧めします。
同期タイプのエラー
クライアントとアプリが異なる同期プロトコルを使用する場合、 WrongSyncTypeExceptionが発生します。
SDK は、フレキシブルな同期とパーティションベースの同期の 2 種類の同期をサポートしています。 クライアントがアプリの同期タイプと一致しない同期タイプを使用してアプリに接続すると、間違った同期タイプ エラーが発生します。
間違った同期タイプのエラーから回復するには、バックエンドと一致する同期タイプを使用するようにクライアントを更新します。 これにより、ユーザーは修正を含む新しいバージョンのアプリに更新する必要がある可能性が高くなります。
不適切なFlexible Sync クエリ エラー
アプリ バックエンドでサポートされていない柔軟な同期クエリをサブスクライブしようとすると、 RedFlexibleSyncQueryExceptionが発生します。 これは、次の場合に発生する可能性があります。
柔軟な同期構成でクエリ可能なフィールドとして指定されていないフィールドをクエリする
柔軟な同期でサポートされていない演算子を使用して柔軟な同期クエリを作成する
不適切な柔軟な同期クエリ エラーから回復するには、アプリ構成と互換性のある同期クエリを使用するようにクライアントを更新します。 これにより、ユーザーは修正を含む新しいバージョンのアプリに更新する必要がある可能性が高くなります。
クライアント リセット エラーの処理
Device Syncを使用する場合、クライアントリセットは、Device Sync サーバーがクライアント Realm と同期できなくなった場合にクライアントアプリが実行する必要があるエラー回復タスクです。 この場合、同期機能を復元するには、クライアントが Realm をサーバーと一致する状態にリセットする必要があります。
この状況が発生すると、クライアント上の同期できない Realm には、サーバーにまだ同期されていないデータが含まれている可能性があります。 Realm SDK は、クライアントのリセット プロセス中にそのデータの回復または破棄を試行できます。
クライアントGo リセットが発生する原因の詳細については、App Services ドキュメントの「 クライアントのリセット 」に してください。
クライアントリセット戦略
Realm SDK は、ほとんどのクライアント リセット エラーを自動的に処理するクライアント リセット戦略と、手動の回復戦略を提供します。
自動クライアントリセットと手動クライアントリセット
自動リセット戦略により、Realm を閉じたり通知が欠落したりせずに、ローカル Realm ファイルが同期可能な状態に復元されます。 違いは、バックエンドにまだ同期されていないデバイス上の変更をどのように処理するかによって異なります。 次の戦略は AutoClientResetStratey インターフェースを実装し、自動クライアント リセットをサポートします。
同期されていない変更を回復または破棄する(デフォルト): クライアント リセット ハンドラーは最初に、同期されていない変更の回復を試みます。 復元が失敗した場合、このハンドラーは 同期されていない変更の破棄 戦略に戻り、同期されていないすべてのローカル変更を永続的に削除します。 同期されていない変更の破棄戦略が失敗した場合、ハンドラーは手動回復にフォールバックします。
同期されていない変更を回復する: クライアント リセット ハンドラーは最初に、同期されていない変更の回復を試みます。 復元が失敗した場合、このハンドラーは手動復元にフォールバックします。
同期されていない変更を破棄: この戦略では、最後の同期が成功した以降に行われたすべてのローカルの同期されていない変更を永続的に削除します。 破棄が失敗した場合、このハンドラーは手動復元にフォールバックします。 このモードは、手動データリカバリを処理する場合に推奨されます。
自動的に処理できない特定のクライアント リセット ロジックがアプリで必要な場合は、 ManuallyRecounterUnsyncedchangesStrateyインターフェースを使用して、手動のクライアント リセット ハンドラーを追加することをおすすめするか、または追加する必要がある場合があります。
同期されていない変更を手動で回復する: 独自の手動回復戦略を実装できます。 手動リカバリは、自動クライアントリセットを実行しない唯一の戦略です。 このモードでは、Realm のみをバックアップできます。 可能であれば、 同期されていない変更を破棄する 戦略を使用して、手動リカバリを処理することをお勧めします。
回復によるクライアントリセット
クライアントリカバリは、 Device Sync を構成するとデフォルトで有効になる機能です。
クライアントリカバリを使用するには、 同期されていない変更を回復 するか、 同期されていない変更を回復または破棄する戦略を使用して Realm を構成します。これにより、Realm はほとんどの場合、クライアントのリセット プロセスを自動的に管理します。
クライアントは、スキーマ変更がない場合、またはスキーマの重大でない変更がある場合に、同期されていない変更を回復できます。
アプリがスキーマの重大な変更を行った場合は、自動クライアント回復は実行できません。 重大な変更とは、処理するために追加のアクションが必要になる、サーバー側のスキーマで行うことができる変更です。 このシナリオでは、クライアントリカバリは手動エラークライアントリセットのフォールバックにフォールバックします。
スキーマの重大な変更と重大でない変更の詳細については、App Services ドキュメントの「 重大な変更と重大でない変更のクイック リファレンス」を参照してください。
クライアント回復ルール
クライアントリカバリが有効になっている場合、バックエンドとクライアントの両方が同じオブジェクトに変更を加えた場合に競合が解決される方法など、オブジェクトの統合方法がこれらのルールによって決まります。
クライアントがリセットされる前に同期されなかったローカルで作成されたオブジェクトが同期されます。
オブジェクトがサーバー上で削除されたが、復元されたクライアントで変更された場合は、削除が優先され、クライアントは更新を破棄します。
リカバリ クライアントでオブジェクトが削除されたが、サーバーでは削除された場合、クライアントはサーバーの削除指示を適用します。
同じフィールドへの更新が競合する場合は、クライアント更新が適用されます。
クライアントリセット戦略の指定
同期された Realm を構成するときに、 SyncConfiguration.syncClientResetStrateyプロパティでクライアント リセット戦略を指定できます。
// Specify your client reset strategy in the SyncConfiguration // If you don't specify, defaults to RecoverOrDiscardUnsyncedChangesStrategy val config = SyncConfiguration.Builder(user, setOf(Toad::class)) .initialSubscriptions { realm -> add(realm.query<Toad>(), "subscription name") } .syncClientResetStrategy(clientResetStrategy) // Set your client reset strategy .build()
次のセクションでは、これらのクライアント リセット戦略の使用方法について説明します。
同期されていない変更を回復または破棄する
同期されていない変更を回復または破棄する戦略は、クライアントのリセット中に同期されていないすべてのローカル変更を自動的に回復しようとします。 同期されていない変更を回復するには、 で クライアントリカバリ App Services Appを有効にする必要があります(デフォルトで有効になっています)。
自動回復プロセスが失敗した場合は、同期されていない変更を破棄する戦略に戻ります。 そのプロセス プロセスが失敗した場合は、再度手動リセット戦略にフォールバックします。
この戦略は、最も堅牢なリカバリ プロセスを提供します。 クライアント リセット戦略を指定しない場合の、デフォルトのクライアント リセット動作です。
重要
バックエンドにまだ同期されていないローカル データをアプリケーションが失うことができない場合は、同期されていない変更を回復または破棄する戦略は使用しないでください。
同期されていない変更を回復または破棄する戦略の使用をカスタマイズするには、 ReactiveOrDiscardUnsyncedchangesStrateyインターフェースを実装するクラスを定義します。
インターフェースは、次のコールバック メソッドを提供します。
onBeforeReset : クライアント リセット前に呼び出されます。 リセット前の Realm のインスタンスを提供します。 このコールバックを使用して、クライアントのリセットが開始される前にユーザーに通知できます。
onAfterRecovery : 自動リセットが正常に完了した場合にのみ呼び出されます。 Realm の読み取り専用の前のインスタンスと、最終 Realm の可変インスタンスを提供します。 このコールバックを使用して、クライアントのリセットが完了したことをユーザーに通知できます。
onAfterDiscard : 自動クライアント リセットが失敗し、破棄されたローカル戦略が成功した場合にのみ呼び出されます。 破棄戦略が失敗した場合、このコールバックは呼び出されません。 Realm の読み取り専用の前のインスタンスと、最終 Realm の可変インスタンスを提供します。 このコールバックを使用して、リセットが完了したことをユーザーに通知できます。
onManagerResetFallback : 自動復元と破棄戦略が失敗した場合にのみ呼び出されます。 ローカルの変更を破棄し、ローカル Realm のバックアップを作成できるようにします。 「手動リカバリ フォールバック 」セクションで説明されているように、リセットの失敗を処理するためにこのコールバックを実装します。
次の例は、 RecoverOrDiscardUnsyncedChangesStrategy
とその各コールバックを示しています。
val clientResetStrategy = object : RecoverOrDiscardUnsyncedChangesStrategy { override fun onBeforeReset(realm: TypedRealm) { Log.i("Client reset: attempting to automatically recover unsynced changes") } // Executed before the client reset begins. // Can be used to notify the user that a reset will happen. override fun onAfterRecovery(before: TypedRealm, after: MutableRealm) { Log.i("Client reset: successfully recovered all unsynced changes") } // Executed if and only if the automatic recovery has succeeded. override fun onAfterDiscard(before: TypedRealm, after: MutableRealm) { Log.i("Client reset: recovery unsuccessful, attempting to manually recover any changes") // ... Try to manually recover any unsynced data manuallyRecoverUnsyncedData(before, after) } // Executed if the automatic recovery has failed, // but the discard unsynced changes fallback has completed successfully. override fun onManualResetFallback( session: SyncSession, exception: ClientResetRequiredException ) { Log.i("Client reset: manual reset required") // ... Handle the reset manually here } // Automatic reset failed. }
同期されていない変更の回復
同期されていない変更を回復する戦略は、クライアントのリセット中に同期されていないすべてのローカル変更を自動的に回復することを試みます。 同期されていない変更を回復するには、 で クライアントリカバリ App Services Appを有効にする必要があります(デフォルトで有効になっています)。
ただし、同期されていない変更を 回復して破棄する 戦略とは異なり、自動復元が失敗した場合にローカルの変更を破棄するようにフォールバックすることはありません。 代わりに、変更を手動で回復するためにフォールバックします。 アプリが同期されていないデータを失うことができない場合は、このクライアントリセット戦略を選択することができます。
同期されていない変更を復元する 戦略を使用するには、 ReoverUnsyncedchangesStrateyインターフェースを実装するハンドラーを定義します。
インターフェースは、次のコールバック メソッドを提供します。
onBeforeReset : クライアント リセット前に呼び出されます。 リセット前の Realm のインスタンスを提供します。 このコールバックを使用して、クライアントのリセットが開始される前にユーザーに通知できます。
onAfterReset : 自動リセットが正常に完了した場合にのみ呼び出されます。 Realm の読み取り専用の前のインスタンスと、最終 Realm の可変インスタンスを提供します。 このコールバックを使用して、クライアントのリセットが完了したことをユーザーに通知できます。
onManagerResetFallback : 自動リカバリが失敗した場合にのみ呼び出されます。 ローカルの変更を破棄し、ローカル Realm のバックアップを作成できるようにします。 「手動リカバリ フォールバック 」セクションで説明されているように、リセットの失敗を処理するためにこのコールバックを実装します。
次の例は、 RecoverUnsyncedChangesStrategy
とその各コールバックを示しています。
val clientResetStrategy = object : RecoverUnsyncedChangesStrategy { override fun onBeforeReset(realm: TypedRealm) { Log.i("Client reset: attempting to automatically recover unsynced changes") } // Executed before the client reset begins. // Can be used to notify the user that a reset will happen. override fun onAfterReset(before: TypedRealm, after: MutableRealm) { Log.i("Client reset: successfully recovered all unsynced changes") } // Executed after the client reset is complete. // Can be used to notify the user that the reset is done. override fun onManualResetFallback( session: SyncSession, exception: ClientResetRequiredException ) { Log.i("Client reset: manual reset required") // ... Handle the reset manually here } // Automatic reset failed. }
同期されていない変更の破棄
同期されていない変更を破棄する戦略では、最後の同期が成功した以降に行われたすべてのローカルの変更が永続的に削除されます。 この戦略では、Realm を閉じることなく、通知が完全に機能したままにローカル Realm ファイルを同期可能な状態に復元します。 このプロセスが失敗した場合は、手動リセット戦略にフォールバックします。
これが、手動データリカバリを処理する場合の推奨戦略です。
Device Syncクライアント回復ルールと整合性のないクライアント回復ロジックがアプリで必要な場合、または同期されていないデータの回復を避けたい場合は、この戦略を選択します。
重要
バックエンドにまだ同期されていないローカル データをアプリケーションが失うことができない場合は、同期されていない変更を破棄する戦略は使用しないでください。
同期されていない変更戦略を使用するには、 DiscardUnsyncedchangesStrateyインターフェースを実装するハンドラーを定義します。
インターフェースは、次のコールバック メソッドを提供します。
onBeforeReset : クライアント リセット前に呼び出されます。 リセット前の Realm のインスタンスを提供します。 このコールバックを使用して、クライアントのリセットが開始される前にユーザーに通知できます。
onAfterReset : リセットが完了した場合にのみ呼び出されます。 Realm の読み取り専用の前のインスタンスと、最終 Realm の可変インスタンスを提供します。 このコールバックを使用して、リセットが完了したことをユーザーに通知できます。
onManagerResetFallback : 自動復元と破棄戦略が失敗した場合にのみ呼び出されます。 ローカルの変更を破棄し、ローカル Realm のバックアップを作成できるようにします。 「手動リカバリ フォールバック 」セクションで説明されているように、リセットの失敗を処理するためにこのコールバックを実装します。
次の例は、 DiscardUnsyncedChangesStrategy
とその各コールバックを示しています。
val clientResetStrategy = object : DiscardUnsyncedChangesStrategy { override fun onBeforeReset(realm: TypedRealm) { Log.i("Client reset: attempting to discard any unsynced changes") } // Executed before the client reset begins. // Can be used to notify the user that a reset will happen. override fun onAfterReset(before: TypedRealm, after: MutableRealm) { Log.i("Client reset: attempting to manually recover any unsynced changes") // ...Try to manually recover any unsynced data manuallyRecoverUnsyncedData(before, after) } // Executed after the client reset is complete. // Can be used to notify the user that the reset is done. override fun onManualResetFallback( session: SyncSession, exception: ClientResetRequiredException ) { Log.i("Client reset: manual reset required") // ... Handle the reset manually here } // Automatic reset failed. override fun onError( session: SyncSession, exception: ClientResetRequiredException ) { // No-op } // Deprecated. onManualResetFallback() used instead. }
手動リカバリフォールバック
スキーマの重大な変更が発生した場合など、クライアントのリセットが自動的に完了しない場合、クライアントのリセットプロセスは手動のエラーハンドラーにドロップされます。
これは、次のいずれかの自動クライアント リセット戦略で発生する可能性があります。
同期されていない変更の回復
同期されていない変更を回復または破棄する
同期されていない変更を破棄する
これらの戦略では、クライアント リセット ハンドラーのonManualResetFallback
コールバックで手動クライアント リセットの実装を指定する必要があります。
手動リセット フォールバックによりローカルの変更は破棄され、 ClientResetRequiredException.executeClientResetメソッドを使用してローカル Realm のバックアップを作成できます。
override fun onManualResetFallback( session: SyncSession, exception: ClientResetRequiredException ) { Log.i("Client reset: manual reset required") // You *MUST* close any open Realm instance closeAllRealmInstances(); // `executeClientReset()` creates a backup exception.executeClientReset(); // (Optional) Send backup for analysis handleBackup(recoveryFilePath); // ... Restore the App state by reopening the realm // or restarting the app }
同期されていない変更の手動回復
データ回復プロセスをカスタマイズする必要がある頻度の低いケースには、 同期されていない変更の手動回復 戦略を使用します。 手動データリカバリを処理するには、可能な限り 同期されていない変更を破棄する戦略を使用することをお勧めします。 自動回復ロジックがアプリに適せず、同期されていないローカル データを破棄できない場合にのみ、 同期されていない変更を手動で回復する 戦略を選択する必要があります。
手動リカバリ戦略を使用するには、 ManuallyRecoverUnsyncedchangesStrateyインターフェースを使用して独自のクライアント リセット ハンドラーを定義します。
このメソッドを使用する前に、リセットする Realm のすべてのインスタンスを閉じる必要があります。 手動リカバリのコールバック後、およびクライアントのリセットが実行される前に行われた Realm ファイルへの書込みは同期されません。 また、 ファイルのバックアップを作成し、例外を報告することも推奨します。
ClientResetRequiredException.executeClientReset()
を使用してクライアント リセットを開始します。
クライアント リセットが手動で実行されない場合、次にすべての Realm インスタンスが閉じられ、再度開かれたときに(通常はアプリが再起動された場合)、自動的に実行されます。
クライアント リセット処理をテストします
Device Sync を終了して再度有効にすることで、アプリケーションのクライアント リセット処理を手動でテストできます。
同期を終了して再度有効にすると、以前に同期に接続したことのあるクライアントは、クライアント リセットを実行するまで接続できなくなります。 同期を終了すると、クライアントが同期できるようにするメタデータがサーバーから削除されます。 クライアントは、サーバーから Realm の新しいコピーをダウンロードする必要があります。 サーバーはこれらのクライアントにクライアント リセット エラーを送信します。 したがって、同期を終了すると、クライアントのリセット条件がtriggerされます。
クライアント リセット処理をテストするには:
クライアント アプリケーションからデータを書き込み、同期されるまで待ちます。
Device Sync を終了して再度有効にします。
クライアント アプリを再度実行します。 アプリは、サーバーに接続しようとすると、クライアント リセット エラーを取得します。
警告
クライアント アプリケーションでクライアント リセット処理を反復処理している間に、同期を繰り返し終了して再度有効にする必要がある場合があります。 同期を終了して再度有効にすると、既存のすべてのクライアントは、クライアントのリセットが完了するまで同期できなくなります。 本番環境でこれを回避するには、開発環境でクライアントのリセット処理をテストします。