The race condition in Django?

Summary: is there a race condition in Django sessions and how to prevent it?

I have an interesting problem with Django sessions, which, in my opinion, are related to race conditions due to simultaneous requests from the same user.

This happened in a script to simultaneously download multiple files tested on localhost. I think this makes simultaneous requests from the same user highly probable (low response time due to localhost, long requests due to file downloads). This is still possible for regular requests outside the local host, although less likely.

I am sending a few requests (files) that I think do this:

  • Django automatically retrieves user session *
  • Unrelated code that takes some time
  • Get request.session['files'] (dictionary)
  • Add data about the current file to the dictionary
  • Save dictionary in request.session['files'] again
  • Make sure it has been saved.
  • More unrelated time-consuming code
  • Django automatically saves user session

Here a check of 6. will indicate that the information was really stored in the session. However, future requests indicate that sometimes this happens, sometimes it is not.

I think what happens is that two of these queries (A and B) happen simultaneously. Request A first retrieves request.session['files'] , then B does the same, modifies it and saves it. When A finally finishes, it overwrites the session changes to B.

Two questions:

  • Is this really what is going on? Is django development server multithreaded? On Google, I find pages on how to make it multithreaded, suggesting that this is not the case by default? Otherwise, what could be the problem?
  • If this race condition is a problem, what would be the best way to solve it? This is an inconvenience, but not a security problem, so I would be happy if the chance were significantly reduced.

Getting the session data right before the changes and saving them right after I think it will significantly reduce the likelihood. However, I did not find a way to do this for request.session , only working around it using django.contrib.sessions.backends.db.SessionStore . However, I believe that if I changed it that way, Django would simply overwrite its request.session at the end of the request.

So I need request.session.reload() and request.session.commit() , basically.

+4
source share
3 answers
  • Yes, it is possible that the request will begin before the other is completed. You can verify this by typing something at the beginning and at the end of the view and at the same time run a bunch of request.

  • Indeed, the session is loaded before the presentation and saved after the presentation. You can reload the session with request.session = engine.SessionStore(session_key) and save it with request.session.save() .

Rebooting a session, however, discards any data added to the session before (in or before the view). Saving until reboot may break the boot point. The best way would be to save the files in the database as a new model.

The essence of the answer is to discuss Thomas's answer, which was incomplete, so I posted the full answer.

+4
source

It's right. You can confirm this by looking at django.contrib.sessions.middleware.SessionMiddleware .

Basically, request.session loaded before request hits your view (in process_request ), and it is updated in the session (if necessary) after response leaves your view (in process_response ).

If what I mean is unclear, you can look at the django documentation for Middleware .


The best way to solve the problem will depend on what you are trying to achieve with this information. I will update my answer if you provide this information!

+1
source

Mark just nailed it, just a small addition from me how to download this session:

 for key in session.keys(): # if you have potential removals del session[key] session.update(session.load()) session.modified = False # just making it clean 

The first line is optional, you only need it if some values ​​can be deleted between sessions.

The last line is optional, if you are updating the session then it does not matter.

+1
source

All Articles