sychronize data with lock in Django

Recently, I met a problem in our project. We do some hidden operations in server to release user’s hands. And one of them is that we want to create an unique record in database per user. So, in the beginning, we just checked the database firstly for knowing if the record exists or not through, and then we will create a new record simply if it does not exist in the database. But, unfortunately, we found a strange thing that more than one records would be created in the database. As you see, we only want to get the unique one idealy, but the reality is not what we want. Interesting, right? We discussed this problem for a while without any results.

But we have to resolve it because of the impact to other modules. So, the first step we must reproduce this bug. Please allow me to analyse from start. First of all, the client will check if there is a record exists or not in database. And then the server will create a new one when no data is returned. Obviously, if the client(same login user in different place) sends more than one requests concurrently, the server will create multiple records because one request won’t find a record from the database while another request is writing the data into the database at the same time. (see figure 1)

Figure 1 concurrent requests

So, we need to add a lock on select. When one request is selecting from the database, the others must wait until it released the lock. Fortunately, Django provides a function select_for_update() to add a lock on database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@transaction.atomic
def create(self, request, *args, **kwargs):
params = self.getParam(request)

# validation
serializer = self.get_serializer(data=params)
serializer.is_valid(raise_exception=True)

try:
instance = some_model.objects.select_for_update().get(
created_by=self.request.user)
return Response(..., status=status.HTTP_200_OK)
except some_model.DoesNotExist:
# create a new one ...

return Response(..., status=status.HTTP_201_CREATED, headers=headers)

sychronize data with lock in Django
https://r-future.github.io/post/django-multiple-requests-with-lock/
Author
Future
Posted on
July 25, 2019
Licensed under