pitazzo
pitazzo

Reputation: 1212

Managing concurrency in Django

I'm working on a web app developed with Django, which serves a Rest API in order to book tickets. In order to do that, I've defined some views which interact with the database via the ORM. My app has some critical functions, such as the booking function.

More or less, it has the following structure:

def book(params...):
    # check ticket availability
    # define some stuff which will we added to the new ticket entity
    # save new ticket entity

I don't know how does Django manages concurrency, therefore, I'm worried about the possibility of checking the availability of two bookings at the same time while just having availability for one of them.

How likely is this to happen and which is the best approach to solve it? I've thought about defining that function as atomic, but I don't know how bad would it be for the system performance.

Upvotes: 1

Views: 3123

Answers (2)

fahim kazi
fahim kazi

Reputation: 106

You should lock the resource exclusively until you are finished with it. If nobody else can acquire a lock on the object while you are working on it, you can be sure the object was not changed.

To acquire a lock on a resource we use a database lock. And in django we use select_for_update() for database lock.

check this select_for_update()

For example:

entries = Entry.objects.select_for_update().filter(author=request.user)

All matched entries will be locked until the end of the transaction block, meaning that other transactions will be prevented from changing or acquiring locks on them.

Upvotes: 3

Anoyz
Anoyz

Reputation: 7701

You're right to be worried, you have a typical concurrency problem. Though Django already helps you by natively employing an atomic system in each view (each view is a transaction, and therefore is guaranteed to run entirely with success or do nothing in case of exceptions) this does not entirely solve your problem.

You must guarantee that each read > process > write process is run independently of others, so for example if you have multiple Django threads under the same application, when your "book" function is called you should avoid any other threads from entering this function (or at least the concurrency-sensitive parts). You can achieve this with concurrency controllers like semaphores or monitors. Take a look here and here.

Your code should be something like:

def book(params...):
    LOCK()
    # check ticket availability
    # define some stuff which will we added to the new ticket entity
    # save new ticket entity
    UNLOCK()

Upvotes: 1

Related Questions