Wednesday, November 26, 2014

Re: Preventing race conditions when submitting forms

Hi,

Thanks for the warning on django-concurrency. While it seems to have the right features for me, I hadn't looked at its internals.

I was thinking about the UI for conflicts and I wonder if I should treat these as form validation errors. If we have the original data (D), the other change set (O), and the conflicting change set (C). On form submit, if there has been any change, the submit fails with an error like "Someone else edited this". We can attempt an automatic merge: any fields that are changed in one of O or C, the change is kept. If both O and C change the field (to different values) then we have a conflict. Conflicting fields get validation errors. I reckon the value should be taken from C, and the error message says "someone else changed this to O". Even if there are no conflicts, we still redisplay the form, because there might be some inter-field dependencies that need manual checking. Probably a good idea to highlight fields that changed in O. With this arrangement, if the user just clicks "Save" again, then the change sets will be merged, with conflicts resolved using C, which seems a reasonable default behaviour.

I agree that the optimal workflow is application specific. For example, if this was a request/approval system, and the administrator changes status to "approved" looking at a total cost of $5, if the user simultaneously changes the total cost to $1000000 then we don't want to automatically merge those changes!

Having a timestamp or counter in the model is actually unnecessary. An alternative is to submit the original data with the form save. In fact, to do the merge, we need that data anyway. And it seems neater to have this as a change that's isolated to the form processing layer.

Well, anyway, that's me just thinking aloud. Sounds like the beginnings of a plan for django-concurrency2. If I get a chance I may look at this in more detail.

Thanks for the input guys!

Paul



On Tuesday, November 25, 2014 9:51:54 PM UTC, Cal Leeming wrote:
+1 - conflict resolution is not an easy task, and really depends on your business logic/use case.

It's worth mentioning that the approach django-concurrency uses may not be suitable for your use case, and in my opinion implementing this restriction on a per model basis is not the best approach, especially when handling multiple model scenarios. Also the implementation of django-concurrency is "dumb", if you look at the example it blocks two save() calls despite no fields being changed on them, and I suspect it doesn't attempt to do any sort of checks to see if the updates would have conflicted. This in itself would be enough reason to stay away from the library (if I'm mistaken, let me know).

django-locking is even worse, it uses a shotgun approach of locking the entire model.. I've used systems (as a user) in the past which implement a similar locking system, and they are a UX anti pattern (imho).

Also remember that representing conflicts in the UI is quite important, having an error at the top of the page telling you that a field conflicted really is quite ghetto and doesn't give a good user experience.. Trello handles this nicely, but they put a lot of time/effort into making the whole process seamless.

The above doesn't really answer your original question of "what can I do", but I hope it gives you some insight into the downsides of those other options.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/f0982139-05e7-49d6-b778-e669bda49931%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment