Name:
interface
Value:
Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated Apr 29, 2024

Conflict resolution

Amplify Android v1 is deprecated as of June 1st, 2024. No new features or bug fixes will be added. Dependencies may become outdated and potentially introduce compatibility issues.

Please use the latest version (v2) of Amplify Library for Android to get started. Refer to the upgrade guide for instructions on upgrading your application to the latest version.

Amplify libraries should be used for all new cloud connected applications. If you are currently using the AWS Mobile SDK for Android, you can access the documentation here.

If data synchronization is enabled via AppSync, there can be different versions of the same object on the client and server. Multiple clients may have updated their respective copies of an object. DataStore will converge different object versions by applying conflict detection and resolution strategies. The default resolution is called Auto Merge. This strategy allows collections to grow, and prefers server-side versions of single-field data. Other strategies include Optimistic Concurrency control and Custom Lambda functions. For more information, see the AWS AppSync documentation on conflict handling.

Custom conflict resolution

To select a different conflict resolution strategy, navigate into your project from a terminal and run amplify update api. Choose Conflict resolution strategy to change the conflict detection and resolution strategies.

? Please select from one of the below mentioned services:
`GraphQL`
...
? Select a setting to edit
`Conflict resolution strategy`
? Select the default resolution strategy
Auto Merge
❯ Optimistic Concurrency
Custom Lambda
Learn More

Per model configuration

Note that this flow will also allow you to change the strategy on each individual GraphQL type, though it is recommended to use the same strategy for your whole schema unless you have an advanced use case:

? Do you want to override default per model settings? Yes
? Select the models from below:
❯◉ Post
PostEditor
User
? Select the resolution strategy for Post model Custom Lambda
? Select from the options below (Use arrow keys)
Create a new Lambda Function
Existing Lambda Function

Custom configuration

DataStore has a few optional configurations, such as the ability to specify a custom handler for error messages that take place in any part of the system. You can also specify a custom conflict handler that runs if a mutation is rejected by AWS AppSync during one of the conflict resolution strategies.

Finally you can configure the number of records to sync as an upper bound on items (per-Model) which will be stored locally on the device, as well as a custom interval in minutes which is an override of the default 24 hour "base query" which runs as part of the Delta Sync process.

Custom configuration fields

  • errorHandler - handler function when DataStore encounters an unrecoverable error in one of its ongoing background operations (model synchronization).
  • conflictHandler - handler function when there is a conflict between two local and remote model instances in a sync operation.
  • syncMaxRecords - sets the maximum number of records, from the server, to process from a sync operation.
  • syncPageSize - sets the number of items requested in each page of sync results.
  • syncInterval - sets the duration of time after which delta syncs will not be preferred over base syncs. The default time unit is minutes.
  • doSyncRetry - enables retry on sync failure.
  • syncExpression - sets a sync expression for a particular model to filter which data is synced locally. The expression is evaluated each time DataStore is started. The QueryPredicate is applied on both sync and subscriptions.

Example

The code below illustrates a conflict resolution handler for the Post model that retries a mutation with the same title, but the most recent remote data for all other fields. The conflict resolution handler discards conflicts for all other models (by passing ConflictResolutionDecision.applyRemote() to onDecision.accept(...)).

DataStoreConfiguration config = DataStoreConfiguration.builder()
.errorHandler(error -> {
// handle DataStore exception here
Log.e("YourApp", "Error.", error);
})
.conflictHandler((conflictData, onDecision) -> {
// retry mutation with the same title and the most recent remote data for other fields
if (conflictData.getRemote() instanceof Post) {
Post patched = ((Post) conflictData.getRemote())
.copyOfBuilder()
.title(((Post) conflictData.getLocal()).getTitle())
.build();
onDecision.accept(ConflictResolutionDecision.retry(patched));
} else {
onDecision.accept(ConflictResolutionDecision.applyRemote());
}
})
// Set the duration of time after which delta syncs will not be preferred over base syncs
.syncInterval(1, TimeUnit.DAYS)
// Set the maximum number of records, from the server, to process from a sync operation
.syncMaxRecords(10_000)
// Set the number of items requested in each page of sync results
.syncPageSize(1_000)
.build();
AWSDataStorePlugin dataStorePlugin = AWSDataStorePlugin.builder().dataStoreConfiguration(config).build();
val config = DataStoreConfiguration.builder()
.errorHandler {
// handle DataStore exception here
Log.e("YourApp", "Error.", it)
}
.conflictHandler { conflictData, onDecision ->
// retry mutation with the same title and the most recent remote data for other fields
if (conflictData.remote is Post) {
val patched = (conflictData.remote as Post)
.copyOfBuilder()
.title((conflictData.local as Post).title)
.build()
onDecision.accept(ConflictResolutionDecision.retry(patched))
} else {
onDecision.accept(ConflictResolutionDecision.applyRemote())
}
}
// Set the duration of time after which delta syncs will not be preferred over base syncs
.syncInterval(1, TimeUnit.DAYS)
// Set the maximum number of records, from the server, to process from a sync operation
.syncMaxRecords(10_000)
// Set the number of items requested in each page of sync results
.syncPageSize(1_000)
.build()
val dataStorePlugin = AWSDataStorePlugin.builder().dataStoreConfiguration(config).build()