Patrik Beck
Patrik Beck

Reputation: 2505

Django channels with redis setup on heroku leaking memory

I followed the somewhat outdated guide here: https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django

And successfully setup django app with channels:

> cat requirements.txt 
..
Django==1.10.6
asgi-redis==1.4.3
asgiref==1.1.2
channels==1.1.8
django-redis-cache==1.7.1
daphne==1.4.2
..

> cat Procfile 
web: daphne Landia.asgi:channel_layer --port $PORT --bind 0.0.0.0
worker: python manage.py runworker

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",
        "CONFIG": {
            "hosts": [os.environ.get('REDIS_URL', 'redis://localhost:6379')],
        },
        "ROUTING": "Landia.routing.channel_routing",
    },
}

The problem being is that the redis memory consumption starts at 2M, and gradually, very slowly, over 48 hours or so grows to 50MB when the provisioned space is exhausted and my server essentially starts throwing 5XX.

It can be fixed by flushing redis.

I assuming the channels/redis are not discarding the replies it sends out.

Screenshot with redis mem usage

Any ideas how to fix, or at least debug this problem?

I also use redis for session storage, which I think is the source of leak:

> heroku redis:cli
> info
...
# Keyspace
db0:keys=119,expires=119,avg_ttl=49389233
db1:keys=7749,expires=7749,avg_ttl=1192828136
> select 1
> keys *
...
7757) :1:django.contrib.sessions.cachechnb5cafa749ec3b1b8b6fc20903750f
7758) :1:django.contrib.sessions.cachechn975ee5d806f3b27d6492e3fad8218
7759) :1:django.contrib.sessions.cachechn659906572f30ed388e655b75fbf87

Here's the django channels session setup:

CHANNEL_SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.RedisCache',
        'LOCATION': os.environ.get('REDIS_URL', 'redis://localhost:6379')
    },
}

And usage in consumers.py

@allowed_hosts_only
@channel_session_user_from_http
def ws_connect(message):
    ...


@channel_session_user
def ws_receive(message):
   ...


@channel_session_user
def ws_disconnect(message):
    ...

Is there a way to clean the session info being stored in redis on disconnect, or at least set up sensible TTL for the redis keys?

Upvotes: 2

Views: 1567

Answers (1)

Nicolas Ferrari
Nicolas Ferrari

Reputation: 43

I recently encountered the same problem and my investigation led me to write on the django-users group (short answer is django-channels does NOT manage session deletion, just waiting for it to expire).

I came up doing it myself since the session won't be useful once the WebSocket client is disconnected:

from channels.sessions import session_for_reply_channel

@channel_session_user
def ws_disconnect(message):
    ...
    session = session_for_reply_channel(message.reply_channel.name)
    session.delete(session.session_key)

Hope this will work for you.

Upvotes: 1

Related Questions