Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing sessions from Redis (Django)

I'm using Django and Redis as session engine (also Celery, but that is something else). It works perfectly and I can see an improvement in speed.

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

I have a script that runs every minute to check the active users through some methods and if the user hasn't been active in the latest minute, then the session gets removed. This is done for customer's tracking needs.

This script was working perfectly until I switched to Redis as a session engine. The session gets indeed removed from the DB but not from Redis. I'm not using any Django built-in method for this but my own function:

def clean_sessions():
    stored_sessions = Session.objects.all()
    active_users = active_users(minutes=1)
    active_users_ids = [user.id for user in active_users]
    for session in stored_sessions:
        session_uid = session.get_decoded().get('_auth_user_id')
        if not session_uid:
            session.delete()
            continue
        if session_uid not in active_users_ids:
            user = User.objects.get(pk=session_uid)
            ## some code between ##
            session.delete()

My question is, how do I remove the session from the cache as well, so the user is actually logged out?

like image 748
Bob Dem Avatar asked Oct 21 '22 03:10

Bob Dem


2 Answers

It wasn't very straightforward but I was able to fix it. I imported this from the file I have my clean_sessions():

from importlib import import_module
from django.conf import settings

Then, inside the function, I loaded the SessionStore object:

SessionStore = import_module(settings.SESSION_ENGINE).SessionStore

From there, it was very easy to remove the sessions, leaving the method like this:

def clean_sessions():
    stored_sessions = Session.objects.all()
    active_users = Request.objects.active_users(seconds=15)
    active_users_ids = [user.id for user in active_users]
    for session in stored_sessions:
        SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
        s = SessionStore(session_key=session.session_key)
        session_uid = session.get_decoded().get('_auth_user_id')
        if not session_uid:
            s.delete()
            continue
        if session_uid not in active_users_ids:
            ## some code ##
            s.delete()

It's very important to load the right SessionStore from whatever session engine you're using, otherwise it will fail to remove it from both places (DB and cache).

like image 141
Bob Dem Avatar answered Oct 27 '22 23:10

Bob Dem


In case someone else needs this for clearing all session data (e.g during tests) depending on backend In this case Redis and The database:

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

REDIS = "django.contrib.sessions.backends.cache"
DATABASE = "django.contrib.sessions.backends.db"
REDIS_AND_DATABASE = "django.contrib.sessions.backends.cached_db"


def clear_all_session_data_globally():
    """
    This will log out every user instantly and delete whatever they were working on, use with caution
    :return:
    """
    if settings.SESSION_ENGINE in [REDIS, REDIS_AND_DATABASE]:
        # Warning this deletes everything from your cache, not just session data
        get_redis_connection(getattr(settings, 'SESSION_CACHE_ALIAS', 'default')).flushall()

    if settings.SESSION_ENGINE in [DATABASE, REDIS_AND_DATABASE]:
        Session.objects.all().delete()
like image 28
Dr Manhattan Avatar answered Oct 27 '22 23:10

Dr Manhattan