Timeline
This is a follow-up from this week’s dev call, where we discussed how syncing and merging works in farmOS.js and Field Kit. @Symbioquine proposed a hypothetical situation where there might be issues with the syncing logic.
7am
We assume 2 users have a copy of an animal asset, ASSET_1, stored on their phones in Field Kit, as well as on the farmOS server. They’re all in the same state, although there’s a little additional metadata on the Field Kit devices.
- farmOS Server
- Initial state of ASSET_1
-
{ changed: 6am, status: active, archived: null, }
-
- Initial state of ASSET_1
- Field Kit A
- Initial state of ASSET_1
-
{ changed: 6am, status: { data: active, changed: 6am }, archived: { data: null, changed: 6am }, }
-
- Initial state of ASSET_1
- Field Kit B
- Initial state of ASSET_1
-
{ changed: 6am, status: { data: active, changed: 6am }, archived: { data: null, changed: 6am }, }
-
- Initial state of ASSET_1
8am
User A takes the asset for slaughter, marks the change, but doesn’t sync to the server.
- Field Kit A
- User sets ASSET_1
-
{ changed: 8am, status: { data: archived, changed: 8am }, archived: { data: 8am, changed: 8am }, }
-
- User sets ASSET_1
10am
User B finds the asset missing, assumes it was taken to slaughter about an hour ago, marks the change, but doesn’t sync.
- Field Kit B
- User sets ASSET_1
-
{ changed: 10am, status: { data: archived, changed: 10am }, archived: { data: 9am, changed: 10am }, }
-
- User sets ASSET_1
12pm
User B goes home for lunch and syncs to the server.
- Field Kit B
- User initiates sync process
- Requests server’s ASSET_1
- farmOS Server
- Sends data for ASSET_1 to Field Kit B
-
{ changed: 6am, status: active, archived: null, }
-
- Sends data for ASSET_1 to Field Kit B
- Field Kit B
- Receives server’s ASSET_1
- Merges local and remote, Last-Write-Wins, so local remains unchanged
-
{ changed: 10am, status: { data: archived, changed: 10am }, archived: { data: 9am, changed: 10am }, }
-
- Sends data for ASSET_1 to server
-
{ changed: 10am, status: archived, archived: 9am, }
-
- farmOS Server
- Receives Field Kit B’s ASSET_1
- Updates ASSET_1
-
{ changed: 10am*, status: archived, archived: 9am, }
-
* = This is the one important data point I’m not entirely sure about, but I’m assuming the server accepts the client’s changed
value.
1pm
User A gets back from the slaughterhouse and syncs with the server.
- Field Kit A
- User initiates sync process
- Requests server’s ASSET_1
- farmOS Server
- Sends data for ASSET_1 to Field Kit A
-
{ changed: 10am, status: archived, archived: 9am, }
-
- Sends data for ASSET_1 to Field Kit A
- Field Kit A
- Receives server’s ASSET_1
- Merges local and remote, Last-Write-Wins, so local is overwritten
-
{ changed: 10am, status: { data: archived, changed: 8am* }, archived: { data: 9am, changed: 10am }, }
-
- No more recent changes, so no updates sent to server
* = If I recall correctly this is what happens, since the values haven’t changed. I should probably check the code again, but I’m not sure it matters either way.
Conclusions
The more accurate data gets overwritten in this case, but I still don’t know if there’s any way around this, programmatically at least. The underlying assumption is that newer data is more trustworthy, hence the Last-Write-Wins approach, but short of discarding that approach, which I still believe is correct, I don’t think there’s much we can do about this.