MongoDB Realm Android Java SDK修改Schema后无法触发Client Reset问题
我使用MongoDB官方示例代码修改Schema后,无法触发Client Reset,但通过在Atlas中切换Sync可以完成该操作。即使修复Schema后,Client Reset仍无法触发,请问是否有方法可以知晓Client Reset的触发时机?
以下是官方参考示例代码:
String appID = YOUR_APP_ID; // replace this with your App ID App app = null; AtomicReference<App> globalApp = new AtomicReference<>(app); // accessing the app from within the lambda below requires an effectively final object app = new App(new AppConfiguration.Builder(appID) .defaultSyncClientResetStrategy(new DiscardUnsyncedChangesStrategy() { @Override public void onBeforeReset(Realm realm) { Log.w("EXAMPLE", "Beginning client reset for " + realm.getPath()); } @Override public void onAfterReset(Realm before, Realm after) { Log.w("EXAMPLE", "Finished client reset for " + before.getPath()); } @Override public void onError(SyncSession session, ClientResetRequiredError error) { Log.e("EXAMPLE", "Couldn't handle the client reset automatically." + " Falling back to manual client reset execution: " + error.getErrorMessage()); // close all instances of your realm -- this application only uses one globalRealm.close(); try { Log.w("EXAMPLE", "About to execute the client reset."); // execute the client reset, moving the current realm to a backup file error.executeClientReset(); Log.w("EXAMPLE", "Executed the client reset."); } catch (IllegalStateException e) { Log.e("EXAMPLE", "Failed to execute the client reset: " + e.getMessage()); // The client reset can only proceed if there are no open realms. // if execution failed, ask the user to restart the app, and we'll client reset // when we first open the app connection. AlertDialog restartDialog = new AlertDialog.Builder(activity) .setMessage("Sync error. Restart the application to resume sync.") .setTitle("Restart to Continue") .create(); restartDialog.show(); } // open a new instance of the realm. This initializes a new file for the new realm // and downloads the backend state. Do this in a background thread so we can wait // for server changes to fully download. ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { Realm newRealm = Realm.getInstance(globalConfig); // ensure that the backend state is fully downloaded before proceeding try { globalApp.get().getSync().getSession(globalConfig).downloadAllServerChanges(10000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } Log.w("EXAMPLE", "Downloaded server changes for a fresh instance of the realm."); newRealm.close(); }); // execute the recovery logic on a background thread try { executor.awaitTermination(20000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } } }) .build()); globalApp.set(app);
Client Reset的触发时机
Client Reset仅在客户端与服务端的同步状态完全无法兼容时才会触发,具体场景包括:
- 客户端Realm的同步历史与服务端完全脱节(比如服务端手动触发了Client Reset、Schema变更属于不兼容类型且服务端强制重置)
- 客户端离线时间超过服务端设置的同步历史保留窗口,服务端已清理对应的同步日志
- 服务端因数据损坏、权限变更等原因,标记该客户端会话需要重置
- 客户端同步会话出现无法自动恢复的致命错误(如数据校验完全失败、无法访问同步服务)
你的场景中,修改Schema后未触发Client Reset,大概率是因为Schema变更属于兼容型变更(比如新增可选字段、修改字段描述),这类变更不会触发服务端强制重置;而切换Atlas Sync相当于重置了服务端的同步状态,才触发了客户端的重置操作。修复Schema后仍无法触发,可能是客户端本地的同步元数据还保留着旧的兼容状态,未触发服务端的重置标记。
监测Client Reset触发时机的方法
监听SyncSession状态
通过SyncSession.addConnectionChangeListener或SyncSession.addProgressListener监听会话状态,当会话进入ClientReset状态时,即为触发时机。依赖自定义回调
你代码中实现的DiscardUnsyncedChangesStrategy的三个回调方法:onBeforeReset:Client Reset开始前触发onAfterReset:Client Reset完成后触发onError:自动重置失败,需要手动处理时触发
这些方法被调用时,直接表明Client Reset正在执行。
查看Realm详细日志
开启Realm的全量日志(设置LogLevel.ALL),搜索ClientResetRequiredError或client reset相关关键词,可获取触发的具体时间和原因。手动触发测试
在Atlas控制台的Sync页面,找到对应客户端ID并执行「Trigger Client Reset」操作,观察客户端的回调是否触发,以此验证你的处理逻辑是否正常。
内容的提问来源于stack exchange,提问作者Vikash Sharma

