1

I am redesigning a large enterprise web system and a major concern has come across the table. The system allows for many users to Create, Read, Update, and Delete items in the system. This is problem if two or more users are editing the same file or item.

What is a good technology or approach to integrate on this? Several things must be considered, for example:

  • User may not delete an item if another user is updating it
  • An item in editing, should be eventually released so that the user is not holding on to it forever and prevent someone else from editing it
  • Make new items/new changes available even while on editing mode (for example, in Stack Exchange, if someone posts an answer to this question while I am writing my own, a dialog appears that says an answer has been posted to this question. I am not able to see it, but as soon as I finish my edit, I can see the answer without refreshing the screen)

If your suggestion comes with more features out of the box or you have any added suggestions or caveats, I am open to them.

Thanks

LOTUSMS
  • 121
  • 1
  • 8
  • I don't think your third point has anything to do with the question. Your editing a question has nothing to do with someone else editing an answer as far as conflicts go. It's just data linked to the question getting selected again in the background. There's no need to protect the question record. – JeffO Mar 29 '17 at 12:32
  • 1
    Have you researched anything on the subject? – JeffO Mar 29 '17 at 12:34
  • I have. But I have found nothing of value. – LOTUSMS Mar 29 '17 at 12:50
  • 2
    http://softwareengineering.stackexchange.com/questions/184047/how-do-you-handle-multiple-users-editing-the-same-piece-of-data-in-a-webapp – JeffO Mar 29 '17 at 13:31
  • I saw that. The answer has a reference to a broken link and a wikipedia. All very vague. I was hoping for much better guidance. – LOTUSMS Mar 29 '17 at 13:46
  • @LOTUSMS: Actually, the link to Optimistic concurrency control (https://en.wikipedia.org/wiki/Optimistic_concurrency_control) is probably what I would have suggested. This question http://softwareengineering.stackexchange.com/questions/239127/strategies-to-manage-multiple-clients-able-to-simultaneously-edit-same-data seems similar to yourquestion. This answer http://stackoverflow.com/questions/833/editing-database-records-by-multiple-users links to https://docs.microsoft.com/en-us/aspnet/web-forms/overview/data-access/editing-inserting-and-deleting-data/implementing-optimistic-concurrency-cs – FrustratedWithFormsDesigner Mar 29 '17 at 14:21
  • 1
    @FrustratedWithFormsDesigner These are all new to me. They didn't come up in my search. All great! These give me a direction to look into. Thanks – LOTUSMS Mar 29 '17 at 15:11
  • 3
    Possible duplicate of [How do you handle multiple users editing the same piece of data in a webapp?](http://softwareengineering.stackexchange.com/questions/184047/how-do-you-handle-multiple-users-editing-the-same-piece-of-data-in-a-webapp) – Greg Burghardt Mar 29 '17 at 15:17
  • @LOTUSMS - Search on Optimistic and Pessimistic locking. Most RDMS systems support both. – Jon Raynor Mar 29 '17 at 20:19

2 Answers2

5

There are generally four options to handle collaborative data maintenance in a multi-user system:

  1. Just overwrite it. Mindlessly process requests in the order they arrive at the server. When user B tries to update an item which user A just deleted, just give an error message "this item doesn't exist". When user A and user B update the same item just milliseconds apart, you take the last one. Simple, crude and prone to mistakes, but can be appropriate in some situations.
  2. Locking and unlocking. Before a user can update a record, they first need to lock it. Only one user at a time can have a dataset locked. When someone else tries to lock it, they get an error message "User XYZ is currently editing this item". When they save the data (or abort the edit), the dataset is unlocked.
  3. Versioning and conflict resolution. Whenever a user saves an item, a new version is created. When someone else created a conflicting version in the meantime, any differences are shown to the user and they can decide how to resolve the conflicts.
  4. Real-time collaborative editing. Users get notified when another user is editing the same item. They can see each other's cursors and selections. Changes appear on each other's screens in real-time. (e.g. Etherpad)

Which solution is the best depends on your business needs. The most important aspect is usually how long your users will take to update a record. When it's a matter of seconds, you would prefer the first option. When it's a matter of minutes, you would prefer the second option. When an update can take an hour or longer, you would prefer the third option.

The fourth option can be really neat for some kinds of highly collaborative work, especially in an environment where users can't communicate directly. But it isn't always appropriate. It can also be very difficult to implement in a user-friendly manner. You might also want to add a meta communication-channel, so users don't need to communicate by writing into the data itself ("Description: This item is a PETER GO AWAY I WAS HERE FIRST!!").

Philipp
  • 23,166
  • 6
  • 61
  • 67
  • I suggested 3 and that was a no-no. Apparently, for reasons unknown to me, the back end developers and data analysts found it to be problematic with the data model. Step 2, from the front end perspective seems to be the most ideal. I am concerned with User B locking an item on Friday and going away on vacation Saturday morning for a week. Step 1 can become a war of the edits. But doable. However, correct me if I am wrong, this needs User B to work on a copy of the item while data remains intact until it is final. Correct? – LOTUSMS Mar 29 '17 at 15:18
  • Fourth is neat but overkill for this system. But very neat indeed. – LOTUSMS Mar 29 '17 at 15:20
  • #3 is what most wikis (at submission) and (distributed) version control systems (at a specifig merge/pull step) do, if you need inspiration. – Weaver Mar 29 '17 at 15:24
  • 1
    @LOTUSMS *"I am concerned with User B locking an item on Friday and going away on vacation Saturday morning for a week"* - you can avoid that by automatically unlocking an item when the user closes the application. So it would only be a problem when the user forgets to shut down their computer before they go on vacation. – Philipp Mar 29 '17 at 15:32
  • @Philipp: Or using time-limited locks. You could either have a job that runs every *n* minutes and removes old locks. The front-end would have to notify the user that their lock has expired. Or, remove locks on access, if the lock is older than *n* minutes. In this scenario, it's harder to notify the user that their lock has expired after *n* minutes of inactivity because the system is only aware when the locked item is accessed. If you want, you could allow for locks to be refreshed if the locking user re-loads the data, or clicks a "re-lock" button or something... – FrustratedWithFormsDesigner Mar 29 '17 at 15:56
  • 1
    The time lock is getting a lot of positive nods around the conference room as we speak. – LOTUSMS Mar 29 '17 at 15:59
1

In addition to Philipp's answer is one more that I use in quite a few systems which is notficaion and override.

It's kind of like #1 and #2 combined.

Say you have a text body, you md5 (or CRC, or something else cheap, I user updated_at) your record. Then send that with the record. Then as the record comes back if that "hash" doesn't match then another "override" parameter needs to be included.

So for example, you have a document, it has body, and hash.

When you post the document,

  • if the hash matches (no changes) then just blind write.
  • if the hash does not match (changes) then throw an error (that the document form can work from)
  • if the hash does not match AND the override param is present, blind write.

Works well when you have a change that could take a wile, so you don't want to just blind write, but when most of the time that is exactly what happens anyway.

Also works well in JSON or other transports. Can be contained entirely in the data layer (You UI layer needs to display the error, of course, but the check and override is in data), and is backwards compatible with clients/front ends that don't support the override (they just get an error), and works VERY well when users are fighting automation (imports, for example.)

coteyr
  • 2,420
  • 1
  • 12
  • 14
  • Sounds like you are onto something but I'm not sure I follow entirely. – LOTUSMS Mar 29 '17 at 15:57
  • lets peretend a web for. I call READ and get back {"too", 3} I UPDATE {"to", 3} in the UPDATE method, if the database has "purple" then the check (3) is not valid, and I need to do something. So I error on the UPDATE and redisplay the form, this time with a checkbox that says ovrride. a call UPDATE {"to", 3, true} and this is blind written to the DB. The check is in the database. so I don't have to rely on ANY front end. The result of a UPDATE on a chained record is by default FAIL, but I provide a way around that FAIL that can be used by whatever reasoning exists. – coteyr Mar 29 '17 at 16:02
  • Same time, if I run a antomated task I could call UPDATE {'frog', 0, true} and it would just work, but would likely still notify the user that the record in the database has changed and they should review. On the web form, win form, API call whatever I can do all manor of fancy to help the user or program decide, but in the end the I have a nice system that means something has to "decide" to override an existing change on a call to UPDATE if there is one. – coteyr Mar 29 '17 at 16:05