Repository metrics
- Stars
- (3 個のスター)
- PR merge metrics
- (PR metrics pending)
説明
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 RERUM API.
The object being updated is...
let orig = {
"@id":"http://devstore.rerum.io/v1/id/123123123123",
"type" : "Message",
"good-bye" : "moon",
"__rerum" : {...}
}
it so happens a client did the following
orig.label = "Good Morning!"
Then
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 in the client now the following
{
"@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 client 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
{
"@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
{
"@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 client cannot /update their way out of this scenario. It has to identify the conflicting node and delete it.
It is likely the client will never know what to do to fix this, and so the user contacts us about seeing the wrong data. Every time this happens.
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 RERUM API "Conflict Safe" update
When you go to /update, first get the MongoDB Object with _id:123123123123. If it has __rerum.history.next, the conflict safe update should return a RESTful code and message about how this would create a conflict. The client can then react how they want-- get confirmation about the conflict then and have a UI for conflict resolution, or force a page refresh to make sure they 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. We would need RERUM Sockets to allow this collaboration.
Should v1 have a conflict safe /update available, and should it be the PUT /update by default?