同期エラーの処理 - C++ SDK
項目一覧
同期エラーの処理
Device Sync を使用するアプリケーションを開発する際には、エラー ハンドラーを設定する必要があります。 このエラー ハンドラーは、失敗した同期関連の API 呼び出しを検出し、応答できます。
sync_configでエラー ハンドラーを設定します。 エラーが発生すると、C++ SDK はsync_errorオブジェクトとエラーが発生したsync_sessionを使用してエラー ハンドラーを呼び出します。
auto appConfig = realm::App::configuration(); appConfig.app_id = APP_ID; auto app = realm::App(appConfig); auto user = app.login(realm::App::credentials::anonymous()).get(); auto dbConfig = user.flexible_sync_configuration(); // Setting an error handler on the sync_config gives you access to // sync_session and sync_error dbConfig.sync_config().set_error_handler( [](const realm::sync_session &session, const realm::internal::bridge::sync_error &error) { std::cerr << "A sync error occurred. Message: " << error.message() << std::endl; }); auto syncRealm = realm::db(dbConfig);
Tip
一般的な Device Sync エラーのリストとその処理方法については、App Services Device Sync ドキュメントの「同期エラー 」を参照してください。
クライアント リセット
Device Syncを使用する場合、クライアントリセットは、サーバーがデバイスデータベースと同期できなくなった場合にクライアントアプリが実行する必要があるエラー回復タスクです。 この場合、同期機能を復元するには、デバイスがデータベースをサーバーと一致する状態にリセットする必要があります。
この状況が発生した場合、デバイス上の同期できないデータベースには、サーバーにまだ同期されていないデータが含まれている可能性があります。 SDK は、クライアントのリセット プロセス中にそのデータの回復または破棄を試行できます。
クライアント リセットが発生する可能性のある原因について詳しくGo は、Atlas App Services ドキュメントの「 クライアントのリセット 」に してください。
自動クライアントリセットと手動クライアントリセット
SDK は、ほとんどのクライアント リセット エラーを自動的に処理するクライアント リセット モードを提供します。 自動クライアント リセット モードでは、データベースを閉じたり通知が欠落したりすることなく、デバイスのデータベースファイルが同期可能な状態に復元されます。
manual()
を除くすべてのクライアント リセット モードで、自動クライアント リセットが実行されます。 モード間の違いは、バックエンドにまだ同期されていないデバイス上の変更をどのように処理するかに基づいています。
ほとんどのクライアント リセット シナリオを自動的に処理するには、 recover_unsynced_changes()
を選択します。 これは、クライアントがリセットしたときに同期されていない変更を回復しようとします。
場合によっては、クライアント リセット ハンドラーを手動で設定する必要があるか、または設定する必要がある場合があります。 自動的には処理できない特定のクライアント リセット ロジックがアプリで必要とされる場合は、これを実行することをお勧めします。
クライアントリセットモードの指定
C++ SDK には、データベース構成でクライアント リセット ハンドラーを指定するオプションが用意されています。 このクライアント リセット ハンドラーはclient_reset_mode_baseを指定できます。 この構造体では以下を指定できます。
クライアントがリセットする前に実行するブロック
クライアントがリセットした後に実行するブロック
クライアントのリセットを処理するときに使用するモード
auto user = app.login(realm::App::credentials::anonymous()).get(); auto syncConfig = user.flexible_sync_configuration(); // Set the client reset handler with your preferred client reset mode. syncConfig.set_client_reset_handler( realm::client_reset::recover_unsynced_changes(beforeReset, afterReset)); auto syncedRealm = realm::db(syncConfig);
使用可能なクライアント リセット モードのいずれかを使用して、クライアント リセット中に SDK がデバイス上の同期されていないデータの解決を試みる方法を指定できます。
recover_unsynced_changes()
recover_or_discard_unsynced_changes()
discard_unsynced_changes()
manual()
自動クライアント リセット プロセス中に実行するブロックの前後を指定できます。 これを使用して、アプリケーションにとって重要なリカバリ ロジックを実行することがあります。
/* You can define blocks to call before and after the client reset occur if you need to execute specific logic, such as reporting or debugging. */ auto beforeReset = [&](realm::db before) { /* A block called after a client reset error is detected, but before the client recovery process is executed. You could use this block for any custom logic, reporting, debugging etc. You have access to the database before the client reset occurs in this block. */ }; auto afterReset = [&](realm::db device, realm::db server) { /* A block called after the client recovery process has executed. This block could be used for custom recovery, reporting, debugging etc. You have access to the database that is currently on the device - the one that can no longer sync - and the new database that has been restored from the server. */ };
アプリに特定のクライアント回復が必要な場合は、 manual()
クライアント リセット モードを指定し、手動のクライアント リセット ハンドラーを設定できます。 クライアント リセット中にアプリで実行する必要がある特定のカスタム ロジックがある場合、またはクライアント回復ルールがアプリで機能しない場合は、この操作を行うことがあります。
スキーマの変更の処理
クライアントリカバリは、 Device Sync を構成するとデフォルトで有効になる機能です。 クライアントリカバリが有効になっている場合、SDK はほとんどの場合、クライアントのリセットプロセスを自動的に管理できます。 スキーマを変更する際:
クライアントは、スキーマ変更がない場合、またはスキーマの重大でない変更がない場合に、同期されていない変更を回復できます。
スキーマの重大な変更を行うと、自動クライアント リセット モードは手動エラー ハンドラーにフォールバックします。 この場合は、手動のクライアント リセット エラー ハンドラーを設定できます。 アプリがスキーマの重大な変更を行った場合は、自動クライアント回復は実行できません。
スキーマの重大な変更と重大でない変更の詳細については、「 重大な変更と重大でない変更のクイック リファレンス 」を参照してください。
同期されていない変更の回復
クライアントのリセット中に、クライアント アプリケーションは、バックエンドにまだ同期されていないデバイス上の 同期されたデータベース 内のデータの回復を試行できます。 同期されていない変更を回復する には、 App Services App で クライアント回復 を有効にする 必要があります。これはデフォルトで有効になっています。
まだ同期されていない変更をアプリで回復するには、次のいずれかのクライアント回復モードを使用します。
recover_unsynced_changes()
: クライアントが同期されていない変更の復元を試みます。 同期されていない変更を破棄するために失敗したくない場合は、このモードを選択します。recover_or_discard_unsynced_changes()
: クライアントは最初に、まだ同期されていない変更の回復を試みます。 クライアントが同期されていないデータを復元できない場合、同期されていない変更を破棄しますが、クライアントのリセットの自動実行は続行されます。 同期されていない変更を破棄するためにバックアップする自動クライアントリカバリを有効にする場合は、このモードを選択します。
auto user = app.login(realm::App::credentials::anonymous()).get(); auto syncConfig = user.flexible_sync_configuration(); // Set the client reset handler with your preferred client reset mode. syncConfig.set_client_reset_handler( realm::client_reset::recover_unsynced_changes(beforeReset, afterReset)); auto syncedRealm = realm::db(syncConfig);
スキーマの変更が重大な場合や、Device Sync 構成でクライアントリカバリが無効になっている場合など、クライアントのリセット操作がrecover_unsynced_changes()
モードで完了しない場合があります。 この場合、アプリは 同期エラー ハンドラーでクライアント リセット エラーを処理できます。 詳細については、このページの「手動クライアント リセット モード」のセクションを参照してください。
クライアント回復ルール
クライアントリカバリが有効になっている場合、バックエンドとクライアントの両方が同じオブジェクトに変更を加えた場合に競合が解決される方法など、オブジェクトの統合方法がこれらのルールによって決まります。
クライアントがリセットされる前に同期されなかったローカルで作成されたオブジェクトが同期されます。
オブジェクトがサーバー上で削除されたが、復元されたクライアントで変更された場合は、削除が優先され、クライアントは更新を破棄します。
リカバリ クライアントでオブジェクトが削除されたが、サーバーでは削除された場合、クライアントはサーバーの削除指示を適用します。
同じフィールドへの更新が競合する場合は、クライアント更新が適用されます。
同期されていない変更の破棄
discard_unsynced_changes()
クライアントリセットモードでは、最後の同期が成功して以降にデバイス上の同期されていないすべての変更が永続的に削除されます。 Device Syncクライアント回復ルールと整合性のないクライアント回復ロジックがアプリで必要な場合、または同期されていないデータを回復したくない場合は、このモードを使用できます。
バックエンドにまだ同期されていないデバイス データをアプリケーションが失うことができない場合は、同期されていない変更モードを使用しないでください。
同期されていない変更を破棄する自動クライアントリセットを実行するには、 discard_unsynced_changes()
クライアント リセット モードを使用します。
auto user = app.login(realm::App::credentials::anonymous()).get(); auto syncConfig = user.flexible_sync_configuration(); // Set the client reset handler with your preferred client reset mode. syncConfig.set_client_reset_handler( realm::client_reset::discard_unsynced_changes(beforeReset, afterReset)); auto syncedRealm = realm::db(syncConfig);
注意
リカバリを使用して破棄
同期されていない変更の復元を試み、復元できない変更を破棄する場合は、このページの「同期されていない変更の復元」セクションのrecover_or_discard_unsynced_changes()
のドキュメントを参照してください。
スキーマの重大な変更が発生した場合など、クライアントのリセット操作がdiscard_unsynced_changes()
モードで完了しない場合があります。 この場合、アプリは 同期エラー ハンドラーでクライアント リセット エラーを処理できます。 詳細については、このページの「 手動クライアント リセット モード 」セクションを参照してください。
手動クライアントリセットモード
manual()
クライアント リセットモードを使用する場合は、同期エラー ハンドラーにカスタム クライアント リセット ハンドラーを実装する必要があります。 可能な場合は自動クライアント回復モードを使用し、自動回復ロジックがアプリに適していない場合にのみmanual()
モードを選択することをお勧めします。
auto user = app.login(realm::App::credentials::anonymous()).get(); auto syncConfig = user.flexible_sync_configuration(); // Set the client reset handler to manual client reset mode. syncConfig.set_client_reset_handler(realm::client_reset::manual()); // Define a Sync error handler for handling the client reset. syncConfig.sync_config().set_error_handler( [&](realm::sync_session session, realm::sync_error error) { if (error.is_client_reset_requested()) { /* You might use this for reporting or to instruct the user to delete and re-install the app. */ }; }); auto syncedRealm = realm::db(syncConfig);
スキーマに重大な変更があった場合など、クライアントのリセット操作が自動的に完了しない場合、クライアント リセット プロセスは手動エラー ハンドラーに降格します。 これは、次のいずれかの自動クライアント リセット モードで発生する可能性があります。
recover_unsynced_changes()
recover_or_discard_unsynced_changes()
discard_unsynced_changes()
アプリをアップデートしたり、その他のアクションを実行するようユーザーに提案する場合、致命的なエラー回復ツールとして手動ハンドラーを使うことをお勧めします。
クライアント リセット処理をテストします
Device Sync を終了して再度有効にすることで、アプリケーションのクライアント リセット処理を手動でテストできます。
同期を終了して再度有効にすると、以前に同期に接続したことのあるクライアントは、クライアント リセットを実行するまで接続できなくなります。 同期を終了すると、クライアントが同期できるようにするメタデータがサーバーから削除されます。 クライアントは、サーバーから Realm の新しいコピーをダウンロードする必要があります。 サーバーはこれらのクライアントにクライアント リセット エラーを送信します。 したがって、同期を終了すると、クライアントのリセット条件がtriggerされます。
クライアント リセット処理をテストするには:
クライアント アプリケーションからデータを書き込み、同期されるまで待ちます。
Device Sync を終了して再度有効にします。
クライアント アプリを再度実行します。 アプリは、サーバーに接続しようとすると、クライアント リセット エラーを取得します。
警告
クライアント アプリケーションでクライアント リセット処理を反復処理している間に、同期を繰り返し終了して再度有効にする必要がある場合があります。 同期を終了して再度有効にすると、既存のすべてのクライアントは、クライアントのリセットが完了するまで同期できなくなります。 本番環境でこれを回避するには、開発環境でクライアントのリセット処理をテストします。