1

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.

Community
  • 1
  • 1

1 Answers1

0

The key here is to acquire the update lock before you check if the conditions are satisfied. Once you have the lock, other threads can't change the data, and you're free to check the conditions and update. If there are concurrent requests, the second thread will always wait until the data is updated to check the conditions.

knbk
  • 52,111
  • 9
  • 124
  • 122
  • Hi, @knbk. Yes, this makes sense. _Before_ getting the lock I would see if the current request is for the current level. My question was if this check could be removed. Because, on the client side, such a request could only be send from the current level. But you could do fast click before the response gets back to the client interface. – Razvan Deaconescu Apr 20 '15 at 07:53