On this page
Conflicts arise when two or more users make changes to the same piece of data independently. This can happen due to latency between device and server or loss of connectivity. In this event, Atlas Device Sync automatically uses conflict resolution strategies to merge the changes. Specifically, Device Sync handles conflict resolution using operational transformation, a set of rules that guarantee strong eventual consistency, meaning all clients' versions will eventually converge to identical states. This will be true even if changes were made in a different order.
You must be aware of the rules to ensure consistent results, but the upside is that by following those rules, you can have devices work entirely offline and still converge on meaningful results when they meet.
At a very high level, the rules are as follows:
- Deletes always win.
- If one side deletes an object it will always stay deleted, even if the other side has made changes to it later on.
- Last update wins.
- If two sides update the same property, Device Sync will keep the value from the most recent update.
- Inserts in lists are ordered by time.
- If two items are inserted at the same position, the item that was inserted first will end up before the other item. This means that if both sides append items to the end of a list, will include both items in order of insertion time.
- Primary keys designate object identity.
- If two sides both create objects of the same class with identical primary keys, they will be treated as instances of the same object.
Conflict Resolution Example
Matt and Sarah are working on data for their dog walking business. Matt deletes data on one of their client's dogs, Doug, as they no longer need to walk him. While Sarah is out without internet connection, she edits Doug's required walk time data on her local, offline version, as she does not know about Matt's deletion of Doug's data.
Once Sarah regains internet connection, her change will be sent to the server. The server will send her Matt's deletion operation. As deletes always win according to Device Sync's conflict resolution rules, Matt's deletion is kept rather than Sarah's edit. The server will not send Sarah's edits to Matt's device. The data is again in agreement across Matt and Sarah's devices.
Using integers for counting is a special case. The way that most
programming languages would implement an increment operation (like
+= 1) is to read the value, increment the result, and then store it
back. This will obviously not work if you have multiple parties doing
incrementing simultaneously (they may both read 10, increment it to 11,
and when it merged you would get a result of 11 rather than the intended
To support this common case, we offer a way to express whether you are incrementing (or decrementing) the value, giving enough hints so the merge can reach the correct result. You have the choice to update the entire value or edit it in a way that conveys more meaning, allowing you to get more precise control of the conflict resolution.
Device Sync interprets the value of a string as a whole and does not merge conflicts on a per-character basis. For example, this means that if a character or substring is inserted or deleted within a string, Device Sync will treat this as a replacement of the entire value of the string.
Generally speaking, the conflict resolution of Device Sync should work for most purposes, and you should not need to customize it. That said, the typical way to do custom conflict resolution is to change a property type from string to list. Each side can then add its updates to the list and apply any conflict resolution rules it wants directly in the data model. You can use this technique to implement max, min, first write wins, last write wins, or any other kind of resolution you can think of.
Device Sync implements a conflict resolution system to allow multiple offline writers to write simultaneously and still eventually converge on the same result.
The conflict resolution system follows four rules: deletes always win, the last update wins, inserts in lists are ordered by time, and primary keys designate object identity.
Counters and strings are special cases to be aware of in your client code.