0

I'm using Django Channels in my app to make a person to person chat function. For this I'm using Django Channels channel layers that uses 'Redis' as a backing store.

I have following configuration in the settings.py:

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [os.environ.get('REDIS_URL', ("localhost", 6379))],
        },
    },
}

The CHANNEL_LAYERS is working fine for development when 'hosts' points to localhost. However for production, when I'm trying to make sure that the channel layer can communicate with Redis on Heroku it does not work. Using code as giving in Channels Docs as shown below, gives the following error

import channels.layers
>>> channel_layer = channels.layers.get_channel_layer()
>>> from asgiref.sync import async_to_sync
>>> async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/app/.heroku/python/lib/python3.7/site-packages/asgiref/sync.py", line 223, in __call__
    return call_result.result()
  File "/app/.heroku/python/lib/python3.7/concurrent/futures/_base.py", line 428, in result
    return self.__get_result()
  File "/app/.heroku/python/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
  File "/app/.heroku/python/lib/python3.7/site-packages/asgiref/sync.py", line 292, in main_wrap
    result = await self.awaitable(*args, **kwargs)
  File "/app/.heroku/python/lib/python3.7/site-packages/channels_redis/core.py", line 299, in send
    async with self.connection(index) as connection:
  File "/app/.heroku/python/lib/python3.7/site-packages/channels_redis/core.py", line 835, in __aenter__
    self.conn = await self.pool.pop()
  File "/app/.heroku/python/lib/python3.7/site-packages/channels_redis/core.py", line 73, in pop
    conns.append(await aioredis.create_redis(**self.host, loop=loop))
  File "/app/.heroku/python/lib/python3.7/site-packages/aioredis/commands/__init__.py", line 175, in create_redis
    loop=loop)
  File "/app/.heroku/python/lib/python3.7/site-packages/aioredis/connection.py", line 133, in create_connection
    await conn.auth(password)
  File "/app/.heroku/python/lib/python3.7/site-packages/aioredis/util.py", line 52, in wait_ok
    res = await fut
  File "/app/.heroku/python/lib/python3.7/site-packages/aioredis/connection.py", line 186, in _read_data
    obj = await self._reader.readobj()
  File "/app/.heroku/python/lib/python3.7/site-packages/aioredis/stream.py", line 102, in readobj
    await self._wait_for_data('readobj')
  File "/app/.heroku/python/lib/python3.7/asyncio/streams.py", line 473, in _wait_for_data
    await self._waiter
  File "/app/.heroku/python/lib/python3.7/asyncio/selector_events.py", line 814, in _read_ready__data_received
    data = self._sock.recv(self.max_size)
ConnectionResetError: [Errno 104] Connection reset by peer
James Z
  • 12,209
  • 10
  • 24
  • 44
Rajesh
  • 48
  • 4

1 Answers1

0

So after a lot of research and support from Heroku team, the workable solution is to have the following settings for channel_layers

As per channels_redis docs for specifying hosts, we can create dicts conforming to create_connection which is basically this method:

aioredis.create_connection(address, *, db=0, password=None, ssl=None, encoding=None, parser=None, loop=None, timeout=None)

for the argument 'ssl' we need to pass a new 'ssl.SSLContext'. So the final setting using 'REDIS_TLS_URL' becomes:

import ssl
new_context = ssl.SSLContext() # this sets the verify_mode to 'CERT_NONE'
host = [{
        'address': f'rediss://{REDIS_HOST}:{REDIS_PORT}', # don't miss the 'rediss'!
        'db': REDIS_DB,
        'password': REDIS_PASSWORD,
        'ssl': new_context ,
    }]

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": host,
            "symmetric_encryption_keys": [SECRET_KEY],
        },
    }}

with the above settings the following error

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate c
hain (_ssl.c:1076)

is no longer being thrown!

Dharman
  • 30,962
  • 25
  • 85
  • 135
Rajesh
  • 48
  • 4