处理同步错误 — Flutter SDK
在开发使用 Device Sync的应用程序时,应设立错误处理程序。 此错误处理程序将检测并响应任何失败的同步相关API调用。
添加 syncErrorHandler 属性到 FlexibleSyncConfiguration 创建同步域时。syncErrorHandler
是 SyncErrorHandler 回调函数。SyncErrorHandler
接受 SyncError 作为参数。每当域中出现SyncError
时,就会调用回调函数,并将SyncError
作为其参数。
final config = Configuration.flexibleSync(currentUser, [Car.schema], syncErrorHandler: (SyncError error) { print("Error message${error.message}"); }); final realm = Realm(config);
如果您未指定syncErrorHandler
,则默认行为是将SyncError
打印到控制台。
补偿写入错误
从 Realm Flutter SDK v1.3 开始,您可以获得有关补偿写入错误的详细信息。
void handleCompensatingWrite( CompensatingWriteError compensatingWriteError) { final writeReason = compensatingWriteError.compensatingWrites!.first; print("Error message: ${writeReason.reason}"); // ... handle compensating write error as needed. } final config = Configuration.flexibleSync(currentUser, [Car.schema], syncErrorHandler: (syncError) { if (syncError is CompensatingWriteError) { handleCompensatingWrite(syncError); } }); final realm = Realm(config);
有关详细信息,请参阅 CompensatingWriteError 类 参考文档。
客户端重置
使用 Device Sync 时,客户端重置是一项任务,当 Device Sync 服务器无法再与客户端域同步时,客户端应用程序必须执行该任务。
处于此状态的客户端可以继续运行并在本地保存数据,但在执行客户端重置之前无法发送或接收同步变更集。 客户端必须将其域重置为与服务器匹配的状态,才能恢复同步能力。客户端上的不可同步域可能包含尚未同步到服务器的数据。
Realm 软件开发工具包(Realm SDK)可以尝试在客户端重置过程中恢复或丢弃该数据。Realm 软件开发工具包(Realm SDK)提供了在大多数情况下自动处理客户端重置的方法。
有关可能导致客户端重置的原因的更多信息,请Go Atlas App Services文档中的 客户端重置 。
客户端重置模式
要管理客户端重置进程,您可以在 FlexibleSyncConfiguration.clientResetHandler 中指定客户端重置模式 配置域时的属性。您可以使用以下客户端重置模式:
恢复或丢弃未同步更改模式(默认):在此客户端重置模式下,客户端重置处理程序首先尝试恢复未同步更改。 如果恢复失败,此处理程序将回退到丢弃未同步的更改模式,该模式会删除所有未同步的本地更改。 如果丢弃未同步更改模式失败,则处理程序将回退到手动恢复模式。
恢复未同步更改模式:在此客户端重置模式,客户端重置处理程序首先尝试恢复未同步更改。 如果恢复失败,此处理程序将回退到手动恢复模式。
放弃未同步的更改模式:此客户端重置模式会永久删除自上次成功同步以来所做的所有本地未同步更改。 如果恢复失败,此处理程序将回退到手动恢复模式。
手动恢复模式:此客户端重置模式为您提供了一种实现自己的恢复策略的方法。
以下部分介绍如何使用这些客户端重置模式。
自动与手动客户端重置
Realm SDK 提供了客户端重置模式,可自动处理大多数客户端重置错误。
客户端自动重置模式将本地 Realm 文件恢复到可同步状态,而无需关闭 Realm 或丢失通知。 以下客户端重置模式支持客户端自动重置:
恢复未同步变更模式
恢复或丢弃未同步的变更模式
丢弃未同步更改模式
这些模式之间的差异取决于它们如何处理设备上尚未同步到后端的更改。 仅手动恢复模式不执行自动客户端重置。
选择恢复未同步更改模式以自动处理大多数客户端重置情况。 这会尝试在客户端重置时恢复未同步的更改。
如果您的应用需要无法自动处理的特定客户端重置逻辑,您可能希望或需要将手动客户端重置处理程序添加到自动客户端重置模式。
客户端重置与恢复
客户端恢复是配置 Device Sync 时默认启用的功能。 启用客户端恢复后,Realm 在大多数情况下会自动托管客户端重置过程。进行模式更改时,客户端可以恢复没有模式更改或非中断性模式更改时未同步的更改。
要使用客户端恢复,请将您的域配置为恢复未同步的更改,或者恢复或丢弃未同步的更改客户端重置模式。
启用客户端恢复后,这些规则将决定如何集成对象,包括当后端和客户端都对同一对象进行更改时如何解决冲突:
同步在客户端重置之前未同步的本地创建的对象。
如果一个对象在服务器上被删除,但在恢复的客户端上被修改,则删除优先,客户端丢弃更新。
如果在正在恢复的客户端上删除了对象,而不是在服务器上删除了对象,则客户端将应用服务器的删除指令。
如果对同一字段的更新发生冲突,则应用客户端更新。
有关配置客户端恢复的更多信息,请参阅 Atlas App Services文档中的 客户端恢复 。
当您的应用程序进行中断性模式更改时,无法进行客户端恢复。 重大更改是您可以在服务器端模式中进行的需要执行额外操作来处理的更改。 在这种情况下,客户端重置并回退到手动错误客户端重置回退。
有关中断性与非中断性模式更改的信息,请参阅 Atlas App Services文档中的 中断性与非中断性更改快速参考 。
恢复或放弃未同步更改模式
恢复或放弃未同步的更改模式尝试在客户端重置期间自动恢复所有未同步的本地更改。 如果不指定客户端重置模式,则客户端重置行为默认为恢复或丢弃未同步的更改。 如果自动恢复过程失败,则会转为丢弃未同步更改模式。 如果该过程失败,则会再次退回到手动重置模式。
恢复或丢弃未同步更改模式可提供最稳健的恢复过程。 但是,如果您的应用程序不能丢失尚未同步到后端的本地数据,则不要使用恢复或丢弃未同步的更改模式。
要自定义恢复或丢弃未同步更改模式的使用,请传递 RecoverOrDiscardUnsyncedChangesHandler 回调到Configure.clientResetHandler
。添加以下可选回调方法以扩展处理程序的功能:
onBeforeReset ,SDK 在客户端重置之前调用。您可以使用此回调在客户端重置开始之前通知用户。
onAfterRecovery ,当 且仅当 自动重置成功完成时,SDK 才会调用该函数。您可以使用它来通知用户客户端重置已完成。
onAfterDiscard ,仅当客户端重置失败 且 丢弃本地策略成功时,SDK 才会调用该函数。如果丢弃策略失败,则不会调用此回调。
onManualResetFallback ,SDK 仅在自动恢复和丢弃策略失败时才会调用该函数。实现此回调以处理重置失败,如手动恢复回退部分中所述。
以下示例展示了如何使用RecoverOrDiscardUnsyncedChangesHandler
及其每个回调:
final config = Configuration.flexibleSync(currentUser, schema, clientResetHandler: RecoverOrDiscardUnsyncedChangesHandler( // All the following callbacks are optional onBeforeReset: (beforeResetRealm) { // Executed before the client reset begins. // Can be used to notify the user that a reset is going // to happen. }, onAfterRecovery: (beforeResetRealm, afterResetRealm) { // Executed if and only if the automatic recovery has succeeded. }, onAfterDiscard: (beforeResetRealm, afterResetRealm) { // Executed if the automatic recovery has failed // but the discard unsynced changes fallback has completed // successfully. }, onManualResetFallback: (clientResetError) { // Automatic reset failed. Handle the reset manually here. // Refer to the "Manual Client Reset Fallback" documentation // for more information on what you can include here. }, ));
恢复未同步更改模式
恢复未同步的更改模式尝试在客户端重置期间自动恢复所有未同步的本地更改。 但是,与恢复或丢弃未同步更改模式不同,如果自动恢复失败,此模式不会回退到丢弃本地更改。 相反,它会转而手动恢复更改。
要使用恢复未同步更改模式,请传递 RecoverUnsyncedChangesHandler 回调到Configure.clientResetHandler
。此处理程序提供以下回调方法:
onBeforeReset ,SDK 在客户端重置之前调用。您可以使用此回调在重置开始之前通知用户。
onAfterReset , 当且仅当 自动重置成功完成时,SDK 才会调用该函数。您可以使用此回调在重置成功完成时通知用户。
onManualResetFallback ,SDK 仅在自动恢复和丢弃策略失败时才会调用该函数。您可以实施此回调来处理重置失败,如“手动恢复回退”部分中所述。
以下示例展示了如何使用RecoverUnsyncedChangesHandler
及其每个回调:
final config = Configuration.flexibleSync(currentUser, schema, clientResetHandler: RecoverUnsyncedChangesHandler( // All the following callbacks are optional onBeforeReset: (beforeResetRealm) { // Executed before the client reset begins. // Can be used to notify the user that a reset is going // to happen. }, onAfterReset: (beforeResetRealm, afterResetRealm) { // Executed after the client reset is complete. // Can be used to notify the user that the reset is done. }, onManualResetFallback: (clientResetError) { // Automatic reset failed. Handle the reset manually here. // Refer to the "Manual Client Reset Fallback" documentation // for more information on what you can include here. }, ));
丢弃未同步更改模式
放弃未同步的更改模式会永久删除自上次成功同步以来所做的所有本地未同步更改。 如果您选择使用此客户端重置模式,SDK 会将您的本地 Realm 文件恢复到可同步状态,而无需关闭 Realm,同时保持通知正常运行。 如果此过程失败,则会转回手动恢复模式。
如果您的应用程序不能丢失尚未同步到后端的本地数据,则不要使用恢复或丢弃未同步的更改模式。
要使用丢弃未同步更改模式,请传递 DiscardUnsyncedChangesHandler 回调到Configure.clientResetHandler
。此处理程序提供以下回调方法:
onBeforeReset ,SDK 在客户端重置之前调用。您可以使用此回调在重置开始之前通知用户。
onAfterReset ,当 且仅当 重置成功完成时,SDK 才会调用该函数。您可以使用它来通知用户重置完成。
onManualResetFallback ,SDK 仅在自动恢复和丢弃策略失败时才会调用该函数。您可以实现此回调来处理重置失败,如“手动恢复”部分中所述。
以下示例展示了如何使用DiscardUnsyncedChangesHandler
及其每个回调:
final config = Configuration.flexibleSync(currentUser, schema, clientResetHandler: DiscardUnsyncedChangesHandler( onBeforeReset: (beforeResetRealm) { // Executed before the client reset begins. // Can be used to notify the user that a reset is going // to happen. }, onAfterReset: (beforeResetRealm, afterResetRealm) { // Executed after the client reset is complete. // Can be used to notify the user that the reset is done. }, onManualResetFallback: (clientResetError) { // Automatic reset failed. Handle the reset manually here. // Refer to the "Manual Client Reset Fallback" documentation // for more information on what you can include here. }, ));
手动恢复回退
如果带恢复的客户端重置无法自动完成(例如发生中断性模式更改时),则客户端重置过程将由手动错误处理程序完成。 这可能发生在任何客户端重置模式下:
恢复未同步变更模式
恢复或丢弃未同步的变更模式
丢弃未同步更改模式
您必须在这些模式的客户端重置处理程序的onManualResetFallback
回调中提供手动客户端重置实施。
在onManualResetFallback
中,使用 ClientResetError.resetRealm() 启动客户端重置回调的ClientResetError
参数的方法。 ClientResetError.resetRealm()
通过删除设备上的域并从服务器下载相关数据来执行客户端重置。 在使用此方法之前,您必须关闭正在重置的域的所有实例。
以下示例演示了如何通过丢弃所有未同步的更改来手动处理错误情况:
// Lazily initialize `realm` so that it can be used in the callback // before the realm has been opened. late Realm realm; final config = Configuration.flexibleSync(currentUser, schema, // This example uses the `RecoverOrDiscardUnsyncedChangesHandler`, // but the same logic could also be used with the `RecoverUnsyncedChangesHandler` // or the `DiscardUnsyncedChangesHandler`. clientResetHandler: RecoverOrDiscardUnsyncedChangesHandler( onManualResetFallback: (clientResetError) { // Prompt user to perform a client reset immediately. If they don't, // they won't receive any data from the server until they restart the app // and all changes they make will be discarded when the app restarts. var didUserConfirmReset = showUserAConfirmationDialog(); if (didUserConfirmReset) { // You must close the Realm before attempting the client reset. realm.close(); // Attempt the client reset. try { clientResetError.resetRealm(); // Navigate the user back to the main page or reopen the // the Realm and reinitialize the current page. } catch (err) { // Reset failed. // Notify user that they'll need to update the app } } }, ));
手动恢复模式
在需要自定义数据恢复过程的极少数情况下,请使用手动恢复模式。 在大多数情况下,应使用其他策略之一进行客户端重置。 如果自动恢复逻辑不适用于您的应用,并且您无法丢弃未同步的本地数据,您可能需要使用手动客户端重置处理程序。
要使用手动恢复模式,请传递 ManualRecoveryHandler 回调到Configure.clientResetHandler
。
该处理程序提供了 onManualReset 回调,您可以在其中执行客户端重置。在onManualReset
中,使用 ClientResetError.resetRealm() 启动客户端重置回调的ClientResetError
参数的方法。 ClientResetError.resetRealm()
通过删除设备上的域并从服务器下载相关数据来执行客户端重置。 在使用此方法之前,您必须关闭正在重置的域的所有实例。
// Lazily initialize `realm` so that it can be used in the callback // before the realm has been opened. late Realm realm; final config = Configuration.flexibleSync(currentUser, schema, clientResetHandler: ManualRecoveryHandler((clientResetError) { // You must close the Realm before attempting the client reset. realm.close(); // Handle manual client reset here... // Then perform the client reset. clientResetError.resetRealm(); }));
测试客户端重置处理
您可以通过终止并重新启用 Device Sync 来手动测试应用程序的客户端重置处理。
当您终止并重新启用 Sync 时,之前使用 Sync 连接的客户端在执行客户端重置之前无法进行连接。 终止同步会从服务器中删除允许客户端同步的元数据。 客户端必须从服务器下载 Realm 的新副本。 服务器向这些客户端发送客户端重置错误。 因此,当您终止同步时,就会trigger客户端重置条件。
要测试客户端重置处理,请执行以下操作:
从客户端应用程序写入数据并等待其同步。
终止并重新启用 Device Sync。
再次运行客户端应用程序。 当应用尝试连接到服务器时,应该会出现客户端重置错误。
警告
当您在客户端应用程序中迭代进行客户端重置处理时,您可能需要反复终止并重新启用 Sync。 终止并重新启用同步会导致所有现有客户端在完成客户端重置之前无法进行同步。 为了避免在生产中出现这种情况,请在开发环境中测试客户端重置处理。