Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
Sync Data

Restablecimiento del cliente - SDK de Java

Tip

Learn More About Client Resets

Para conocer las causas y las estrategias para manejar los restablecimientos de clientes, consulte Sincronización Página de restablecimiento de cliente.

The SDK reads and writes to a realm file on the device. When you use Atlas Device Sync, this local realm syncs with the application backend. Some conditions can cause the realm to be unable to sync with the backend. When this occurs, you get a client reset error.

This error means you must reset the realm file in the client application. Clients in this state may continue to run and save data locally. Until you perform the client reset, the realm does not sync with the backend.

Elija una estrategia de restablecimiento de cliente para gestionar los errores de restablecimiento. Estas estrategias restauran el dominio a un estado sincronizable, pero tienen desventajas:

  • Descartar cambios no sincronizados. Restaurar la sincronización descartando los cambios locales desde la última sincronización. Mantiene los detectores de cambios.

  • Recuperar manualmente cambios no sincronizados: Mueva el realm no sincronizable y descargue una copia nueva. Invalida los escuchadores de cambios.

Both options let you write custom logic to recover local changes. Neither option can recover local changes for you.

Discard unsynced changes is a less complex alternative to manual recovery. However, this strategy cannot handle every client reset error. You must maintain a manual client reset handler as a fallback.

New in version 10.10.0.

Discard unsynced changes is a client reset strategy provided by the SDK. This strategy requires minimal code. This strategy performs a reset without closing the realm or missing notifications.

Elimina todos los cambios locales realizados desde la última sincronización exitosa. Esto incluye cualquier dato ya escrito en el dominio, pero aún no sincronizado con el backend de la aplicación. No utilice esta estrategia si su aplicación no puede eliminar los datos no sincronizados.

Discard unsynced changes cannot handle breaking or destructive schema changes. When breaking changes occur, the SDK falls back to manual recovery mode.

Para usar esta estrategia, pase una instancia de DiscardUnsyncedChangesStrategy al método de construcción defaultSyncClientResetStrategy() cuando cree una instancia de su AppSu instancia DiscardUnsyncedChangesStrategy debe implementar los siguientes métodos:

  • onBeforeReset(). El SDK llama a este bloque cuando recibe un error de restablecimiento del cliente desde el backend. Esto ocurre antes de que el SDK ejecute la estrategia de restablecimiento del cliente.

  • onAfterReset(). The SDK calls this block after successfully executing this strategy. This block provides a frozen copy of the original realm. It also returns a live instance of the realm in a syncable state.

  • onError()El SDK llama a este método durante un cambio de esquema importante. Su comportamiento es similar al de defaultClientResetStrategy().

El siguiente ejemplo implementa esta estrategia:

String appID = YOUR_APP_ID; // replace this with your App ID
App 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 recovery: " + error.getErrorMessage());
handleManualReset(session.getUser().getApp(), session, error);
}
})
.build());
val appID: String = YOUR_APP_ID // replace this with your App ID
val app = App(
AppConfiguration.Builder(appID)
.defaultSyncClientResetStrategy(object : DiscardUnsyncedChangesStrategy {
override fun onBeforeReset(realm: Realm) {
Log.w("EXAMPLE", "Beginning client reset for " + realm.path)
}
override fun onAfterReset(before: Realm, after: Realm) {
Log.w("EXAMPLE", "Finished client reset for " + before.path)
}
override fun onError(session: SyncSession, error: ClientResetRequiredError) {
Log.e(
"EXAMPLE", "Couldn't handle the client reset automatically." +
" Falling back to manual recovery: " + error.errorMessage
)
handleManualReset(session.user.app, session, error)
}
})
.build()
)

Importante

Los cambios importantes en el esquema requieren una actualización del esquema de la aplicación

Después de un cambio de esquema importante:

  • All clients must perform a client reset.

  • Debe actualizar los modelos de cliente afectados por el cambio de esquema importante.

La estrategia de descartar cambios no sincronizados no puede gestionar cambios importantes. Debe gestionar manualmente el restablecimiento del cliente en el método onError(). Este ejemplo descarta manualmente los cambios no sincronizados para gestionar el restablecimiento del cliente:

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);
val appID = YOUR_APP_ID // replace this with your App ID
var app: App? = null
app = App(
AppConfiguration.Builder(appID)
.defaultSyncClientResetStrategy(object : DiscardUnsyncedChangesStrategy {
override fun onBeforeReset(realm: Realm) {
Log.w("EXAMPLE", "Beginning client reset for " + realm.path)
}
override fun onAfterReset(before: Realm, after: Realm) {
Log.w("EXAMPLE", "Finished client reset for " + before.path)
}
override fun onError(session: SyncSession, error: ClientResetRequiredError) {
Log.e(
"EXAMPLE", "Couldn't handle the client reset automatically." +
" Falling back to manual client reset execution: "
+ error.errorMessage
)
// 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 (e: java.lang.IllegalStateException) {
Log.e("EXAMPLE", "Failed to execute the client reset: " + e.message)
// 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.
val restartDialog = 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.
val executor = Executors.newSingleThreadExecutor()
executor.execute {
val newRealm = Realm.getInstance(globalConfig)
// ensure that the backend state is fully downloaded before proceeding
try {
app!!.sync.getSession(globalConfig)
.downloadAllServerChanges(
10000,
TimeUnit.MILLISECONDS
)
} catch (e: InterruptedException) {
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 (e: InterruptedException) {
e.printStackTrace()
}
}
})
.build()
)

Tip

Manual recovery replaces the deprecated SyncSession.ClientResetHandler. Clients using the deprecated handler can update to manual recovery with no logic changes.

No recomendamos la recuperación manual del restablecimiento del cliente. Se requiere:

  • Substantial amounts of code

  • Concesiones de esquema

  • Complex conflict resolution logic.

To learn more, see the Advanced Guide to Manual Client Reset Data Recovery.

Puede probar manualmente el manejo de restablecimiento del cliente de su aplicación finalizando y volviendo a habilitar la sincronización del dispositivo.

When you terminate and re-enable Sync, clients that have previously connected with Sync are unable to connect until after they perform a client reset. Terminating Sync deletes the metadata from the server that allows the client to synchronize. The client must download a new copy of the realm from the server. The server sends a client reset error to these clients. So, when you terminate Sync, you trigger the client reset condition.

To test client reset handling:

  1. Write data from a client application and wait for it to synchronize.

  2. Termina y vuelve a habilitar Device Sync.

  3. Ejecuta la aplicación cliente nuevamente. La aplicación debería obtener un error de restablecimiento del cliente cuando intente conectarse al servidor.

Advertencia

Mientras itera sobre la gestión del restablecimiento de clientes en su aplicación cliente, es posible que tenga que finalizar y volver a habilitar la sincronización repetidamente. Esto impide que todos los clientes existentes puedan sincronizar hasta después de completar un restablecimiento. Para evitar esto en producción, pruebe la gestión del restablecimiento de clientes en un entorno de desarrollo.

Volver

Manejar errores de sincronización

En esta página