I've followed this post (Race conditions in django) regarding race conditions in Django. The select_for_update
solution solves the problem of multiple updates overriding each other.
I have a problem in the same area. I have a quest-like app running on top of Django. A quest has multiple levels; when the user provides a correct answer by filling an answer form and clicking the "Check answer" button he gets promoted to the next level. However, if a user were to provide the correct answer and then click the "Check answer" simultaneously on two browser screens, the server side would get two requests.
On the server side, if the answer is correct, one would also get a level increase. The code is something like:
self.current_level += 1
self.save()
Even if I used a select_for_update
approach, the two requests might be accepted on the client side then reach the server. On the server side they would be processed sequentially and result in a two level increase (instead of just one). This would happen even if using a select_for_update
approach.
The solution I would use, particular to the implementation, is verifying the current level before any update and making sure the current level is the one for the current question (not the next one). Though only rarely would this check fail.
Is there a more generic way to handle these kind of problems? Or would one need to check the current value of the level/object/data and update it only if it matches the expected value? In conjunction with the select_for_update
approach, of course.