Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A tale of offline support an conflict resolution

A tale of offline support an conflict resolution

Mobile devices are not always connected to a reliable Internet connection, but that does not matter that our apps should stope working if they are offline. In this talk I'll explain some approaches the Wunderlist team decided to take in order to provide full offline support.

Antonio J. Consuegra

February 27, 2016
Tweet

More Decks by Antonio J. Consuegra

Other Decks in Technology

Transcript

  1. Who am I? Antonio J. Consuegra Senior Software Engineer @

    Microsoft @aconsuegra +AntonioConsuegra
  2. What IS this talk about? • Offline support matters, a

    lot. • How to synchronise offline data.
  3. What IS this talk about? • Offline support matters, a

    lot. • How to synchronise offline data. • How to resolve conflicts.
  4. Handle offline status like a Pro • Never, never block

    the user. • Only a few calls should require being online.
  5. Handle offline status like a Pro • Never, never block

    the user. • Only a few calls should require being online. • Most of user’s actions can be retried when online.
  6. • Queue them (Priority Job Queue, Job Scheduler, etc.) •

    Save only the last state of an entity… How can you retry API calls?
  7. • Queue them (Priority Job Queue, Job Scheduler, etc.) •

    Save only the last state of an entity… • Save the current “sync” state. & How can you retry API calls?
  8. Sync state public class Entity {
 
 private enum SyncState

    { DIRTY, SYNCING, SYNCED }
 
 private SyncState syncState = SyncState.DIRTY;
 
 public Entity() {
 …
 }
 
 public SyncState getSyncState() { … }
 
 public void setSyncState(SyncState syncState) { … }
 }
  9. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  10. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  11. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  12. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  13. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  14. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  15. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  16. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  17. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  18. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  19. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  20. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  21. Sync state Note text = “Hello” state = SYNCED Note

    text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY Online? YES Note text = “Hey Yo” state = SYNCING Some retry logic Success? Note text = “Hey Yo” state = SYNCED Note text = “Hey Yo” state = DIRTY YES NO NO ☁
  22. Local ID & Online ID • At creation time, a

    local_id is assigned to each entity. • When the entity is synced, it receives an online_id. • Children have to use local_id or online_id to identify its parent.
  23. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  24. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  25. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  26. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  27. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  28. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  29. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  30. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  31. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  32. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  33. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  34. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  35. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  36. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  37. Flush dirty entities Root User List Task Subtask Comment Reminder

    … IF entity is DIRTY ELSE REPEAT with child/sibling SET state to SYNCING PUSH entity to API IF success SET state to SYNCED IF onlineId was NULL UPDATE parentId in children REPEAT with child/sibling ELSE SET state to DIRTY REPEAT with child/sibling
  38. All right, but… • The proposed approach works fine for

    one user/device. • We have to add a revision to each entity. • Every time an entity is updated, its revision is updated by the API.
  39. Revisions ☁ Task title = “Hello” localId = 1 Task

    title = “Hello” localId = 1 onlineId = 1 revision = 1 HTTP POST 201 OK Case 1: Create a new entity
  40. Revisions ☁ Task title = “Hello” localId = 1 Task

    title = “Hello” localId = 1 onlineId = 1 revision = 1 HTTP POST 201 OK Case 1: Create a new entity
  41. Revisions ☁ Task title = “Hello” localId = 1 Task

    title = “Hello” localId = 1 onlineId = 1 revision = 1 HTTP POST 201 OK Case 1: Create a new entity
  42. Revisions ☁ Task title = “Hello” localId = 1 Task

    title = “Hello” localId = 1 onlineId = 1 revision = 1 HTTP POST 201 OK Case 1: Create a new entity
  43. Revisions ☁ Task title = “Hello” localId = 1 Task

    title = “Hello” localId = 1 onlineId = 1 revision = 1 HTTP POST 201 OK Case 1: Create a new entity
  44. Revisions ☁ Case 2: Update an entity Task title =

    “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 HTTP PATCH 200 OK
  45. Revisions ☁ Case 2: Update an entity Task title =

    “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 HTTP PATCH 200 OK
  46. Revisions ☁ Case 2: Update an entity Task title =

    “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 HTTP PATCH 200 OK
  47. Revisions ☁ Case 2: Update an entity Task title =

    “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 HTTP PATCH 200 OK
  48. Revisions ☁ Case 2: Update an entity Task title =

    “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 HTTP PATCH 200 OK
  49. Revisions ☁ Case 3: Delete an entity Task onlineId =

    1 revision = 2 HTTP DELETE 200 OK
  50. Revisions ☁ Case 3: Delete an entity Task onlineId =

    1 revision = 2 HTTP DELETE 200 OK
  51. Revisions ☁ Case 3: Delete an entity Task onlineId =

    1 revision = 2 HTTP DELETE 200 OK
  52. Revisions ☁ Case 3: Delete an entity Task onlineId =

    1 revision = 2 HTTP DELETE 200 OK
  53. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  54. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  55. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  56. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  57. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  58. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  59. Revisions ☁ Case 4: Sync new entities Task title =

    “Hello” localId = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1 Task title = “Hello” localId = 1 onlineId = 1 revision = 1
  60. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  61. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  62. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  63. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  64. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  65. Revisions ☁ Case 4a: Sync updated entities Task title =

    “Hello” onlineId = 1 revision = 1 Task title = “Hello” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 1 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2
  66. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3
  67. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  68. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  69. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  70. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  71. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  72. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  73. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  74. Revisions ☁ Case 4b: Sync updated entities Task title =

    “Hey Yo” onlineId = 1 revision = 2 Task title = “Hey Yo” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 2 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 ⚡
  75. Conflicts ☁ Task title = “Beer!” onlineId = 1 revision

    = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  76. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  77. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  78. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  79. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  80. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  81. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  82. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  83. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  84. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  85. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  86. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  87. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  88. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  89. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  90. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  91. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  92. Conflicts ☁ ⚡ Task title = “Beer!” onlineId = 1

    revision = 3 Task title = “Beer!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 3 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Buuu!!” onlineId = 1 revision = 4 Task title = “Beer!” starred = TRUE revision = 3 409 ERROR Task title = “Buuu!!” starred = TRUE revision = 4 Task title = “Buuu!!” starred = TRUE revision = 5 Task title = “Buuu!!” starred = TRUE revision = 5
  93. Conflicts Resolution • The API returns 409 when the client

    needs to fix a conflict. • Each entity holds a reference to the modified fields. • All platforms use the same algorithm to solve conflicts, we call it ThreeWayMergeResolver.
  94. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  95. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  96. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  97. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  98. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  99. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  100. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  101. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  102. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  103. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  104. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY
  105. ThreeWayMergeResolver IF entity has conflict GET entity from API IF

    success FOR each field in entity IF field was modified locally UPDATE field with local value SET state to DIRTY ELSE IF error code IS 404 DELETE entity locally ELSE RETRY