0

I have created below model tracking user-session relationships:

from django.conf import settings
from django.contrib.sessions.models import Session

USER_MODEL = settings.AUTH_USER_MODEL


class UserSession(models.Model):
    user = models.ForeignKey(USER_MODEL, on_delete=models.CASCADE)
    session = models.ForeignKey(Session, on_delete=models.CASCADE)

And to populate entries of this model, registered below user_logged_in handler:

from django.contrib.auth import get_user_model
from django.dispatch import receiver
from django.contrib.auth.signals import user_logged_in

from accounts.models import UserSession

User = get_user_model()


@receiver(user_logged_in, sender=User, dispatch_uid="handle_user_login")
def handle_user_login(sender, request, user, **kwargs):
    if not request.session.session_key:
        request.session.create()
    UserSession.objects.get_or_create(user=user, session_id=request.session.session_key)

The model and user login handler signal are deployed and working as expected in production. Problem is above mentioned signal sometimes raises database integrity error:

insert or update on table "accounts_usersession" violates foreign key constraint "accounts_usersessio_session_id_fee1fd0b_fk_django_se"
DETAIL:  Key (session_id)=(56aklsn6q00dm7hnszsksokbilj1p444) is not present in table "django_session".

The probability (experimental) of above exception is fairly low at about 0.04%. I couldn't reproduce this error in my local development environment. What can be cause for this error and how can I prevent it?

Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45
  • My assumption is that someone is cleaning up the data in session table. Are you sure you are the only one with DB access? – Underoos Oct 23 '20 at 18:01
  • @Underoos I don't think someone removes data from that table. And as you see I am creating session if session_key is None. And it is just a time of milliseconds between user's login request and firing of this signal. This short time period also decreasing coincidence of overlapping DELETE from database and INSERT INTO usersession table. – Elgin Cahangirov Oct 23 '20 at 18:12
  • Wait a second, why are you creating sessions for users that login? If this is tracking the relation, it should only observe, not create. In fact, by definition users that login that fire this signal have a session and you shouldn't interfere. –  Oct 23 '20 at 20:15
  • @Melvyn session.session_key can be None and I should create new session if so. Look this question: https://stackoverflow.com/questions/39181655/sometimes-request-session-session-key-is-none – Elgin Cahangirov Oct 24 '20 at 06:12
  • No you don't. The answer does a `save()` not a create, which sounds sane to me. Look at the code where the login signal is fired (django.contrib.auth.login), the session key is set, because you cannot login without having a session. –  Oct 24 '20 at 06:48
  • @Melvyn source code shows that create method also calls save after generating unique key. Anyway, I changed create call to save for solution (hopefully). Although I estimate that same integrity error will continue to arise from time to time. – Elgin Cahangirov Oct 24 '20 at 07:31
  • It does, but I'm not sure what happens to the data in the session, since login does manual work to ensure data in the session is handled correctly through the use of `cycle_key()` instead of `create()`. I would catch and log the IntegrityError (or make use of Sentry) to get the traceback. –  Oct 24 '20 at 07:53

0 Answers0