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.
source share