CenterForDigitalHumanities / CenterForDigitalHumanities/TinyNode
Conflict-Safe Updates
- Dominant language
- JavaScript
- Stars
- 1
- Forks
- 3
- Avg merge
- 29m
- Merged PRs (30d)
- 1
Description
We have had this conversation in the past, but it was rehashed when trying to explain how /update works. For the purposes of this issue, assume you only have control over the client side (client API).
The object you want to update is...
```Javascript
let orig = {
"@id":"http://devstore.rerum.io/v1/id/123123123123",
"type" : "Message",
"good-bye" : "moon",
"__rerum" : {...}
}
```
it so happens you do the following
```Javascript
orig.label = "Good Morning!"
```
Then you
```Javascript
let updated_orig = await fetch(UPDATE_URL, {
method: 'PUT',
body: JSON.stringify(orig),
headers: new Headers({
'Content-Type': 'application/json; charset=utf-8'
})
}).then(resp => resp.json())
```
Upon success, updated_orig is now the following
```JSON
{
"@id":"http://devstore.rerum.io/v1/id/aaaeeeaaaeeeaaeae",
"type" : "Message",
"good-bye" : "moon",
"label" : "Good Morning!",
"__rerum" : {history.previous : "http://devstore.rerum.io/v1/id/123123123123"}
}
```
Let's assume this user has two devices that had both pulled up `http://devstore.rerum.io/v1/id/123123123123` at the same time. Let's assume they did this action on Device A. Let's assume a session timeout of 20 minutes.
When the user was done on Device A, they picked up Device B and went to refill their coffee. They had an AHA! moment by the coffee pot, so on Device B they updated `http://devstore.rerum.io/v1/id/123123123123` again. This generated a
```JSON
{
"@id":"http://devstore.rerum.io/v1/id/bbbbcccbcbcbccccbc",
"type" : "Message",
"good-bye" : "moon",
"label" : "Good Morning!",
"aha" : "moment,
"__rerum" : {history.previous : "http://devstore.rerum.io/v1/id/123123123123"}
}
```
When getting back to their computer and refreshing the page, they never see this new data node. The only thing that keeps showing up is
```JSON
{
"@id":"http://devstore.rerum.io/v1/id/aaaeeeaaaeeeaaeae",
"type" : "Message",
"good-bye" : "moon",
"label" : "Good Morning!",
"__rerum" : {history.previous : "http://devstore.rerum.io/v1/id/123123123123"}
}
```
This is because `/query` for `{"type":"Message", "__rerum.history.next" : { "$exists": true, "$size": 0 }}` gives the client script http://devstore.rerum.io/v1/id/aaaeeeaaaeeeaaeae **_AND_** http://devstore.rerum.io/v1/id/bbbbcccbcbcbccccbc. The client script NEVER intended to make "conflicts" and so is arbitrarily picking Leaf in History to show. The user cannot /update their way out of this scenario. They have to identify the conflicting node and delete it.
It is likely the user will never know what to do to fix this, and so they contact us about seeing the wrong data. Every time this happens.
Once they contact us and we fix their data, what do we suggest they do so this doesn't happen again? Note that `/overwrite` is not the solution, as for this same use case it would always show the most recent /overwrite, which in this scenario could still be wrong but easy to /overwrite your way out of.
Suggested Client Side "Conflict Safe" update
"When you go to /update, first resolve the @id of the item you are trying to update. If it has `__rerum.history.next`, then you are viewing stale data. React however you want -- get confirmation about the conflict and have a UI for conflict resolution, or force a page refresh to make sure you have the most recent data".
However, note how this affects collaborative working scenarios, like two people working on the same transcription for the same Canvas/Image in the same Project at the same time.
Should `TinyNode` make an update like this available (bubble that question out to DEER).
Contributor guide
Assessment
This issue has not been assessed yet.