Django and not really reliable sessions

368 views Asked by At

I have lost one day with struggling with django sessions and it seems that I am not really able to resolve it without coding my own sessions middleware or using some locking. The problem is, sessions are not stored even if the saving is triggered manually. It happens now and then, because of race condition which occurs when multiple simultaneous AJAX requests are sent from the client side. I'm using db backend. The thing is, everything is ok when calling only one start() dajaxice call from the javascript side.

So the question, why session is not stored sometimes? Should I lock the segment, where session is being stored? I double checked session_key is still the same. Should not be this resolved in the session middleware module?

Settings: SESSION_SAVE_EVERY_REQUEST = True

def print_session_keys(request, tmp):
    session_key = request.session.session_key
    session = Session.objects.get(session_key=session_key)
    a = session.get_decoded()
    print tmp+str(a.keys())

@dajaxice_register
def start(request):
    dajax = Dajax()

    searchHash = os.urandom(16).encode('hex')

    data = 1

    print_session_keys(request, 'Before: - hash: '+searchHash+' ')
    request.session.set_expiry(0)
    request.session[searchHash] = data
    request.session.modified = True
    request.session.save()
    print_session_keys(request, 'After: - hash: '+searchHash+' ')

LOG:

1 or 2 requestes of 3, are stored fine:

Before: - hash: 05f22e8e828a0e6145519e0bb0778357 [u'b0d0d5e4ebe846c4e3ffa66bfbd2e7e3', u'usermode', u'_session_expiry']
After: - hash: 05f22e8e828a0e6145519e0bb0778357 [u'09cf89e0cbe5fb6a179e1f658d452c6b', u'05f22e8e828a0e6145519e0bb0778357', u'usermode', u'b0d0d5e4ebe846c4e3ffa66bfbd2e7e3', u'_session_expiry']

BUT:

Before: - hash: 071e79041aba16a82a32fe4a77c3b4e0 [u'b0d0d5e4ebe846c4e3ffa66bfbd2e7e3', u'usermode', u'_session_expiry']
After: - hash: 071e79041aba16a82a32fe4a77c3b4e0 [u'09cf89e0cbe5fb6a179e1f658d452c6b', u'05f22e8e828a0e6145519e0bb0778357', u'usermode', u'b0d0d5e4ebe846c4e3ffa66bfbd2e7e3', u'_session_expiry']

UPDATE:

I ended up with using mutex.acquire() and mutex.release(). It now works, but all exceptions must be caught, otherwise mutex will be not released.

mutex.acquire()
try:
    request.session.set_expiry(0)
    request.session[searchHash] = data
    request.session.modified = True
    request.session.save()
except SomeException:
    mutex.release()
    return dajax.json()
mutex.release()

So if you are doing multiple requests, all with the same session_key, you need to use some locking. Session data is fetched before django enters the view. That is why, there are co-existing multiple and different instances of the session with the same session_key. So to briefly describe what is happening:

1) Request 1 fetches session data from db
2) Request 1 hits the view
3) Request 2 fetches session data from db
4) Request 2 hits the view
5) Request 2 saves session[mykey]
6) Request 1 saves OLD session data got from 1) and overwrites session written in 5)

I Hope this may help somebody.

0

There are 0 answers