I am using django chanels for sending real time notification, on the local development server it works fine with redis url redis://127.0.0.1:6379
but when I go to production on Heroku it couldn't connect meanwhile celery works fine on the same redis url on Heroku.
this is the channel layer I am using and the REDIS_URL is set properly in the environment variables both locally and on production.
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [env('REDIS_URL', default='redis://localhost:6379')],
},
},
}
The Error I get is the following:
2023-03-12T13:15:29.051013+00:00 app[web.1]: ERROR 2023-03-12 13:15:29,047 server 2 140084942075712 Exception inside application: Error 1 connecting to ec2-50-17-163-82.compute-1.amazonaws.com:7550. 1. 2023-03-12T13:15:29.051015+00:00 app[web.1]: Traceback (most recent call last): 2023-03-12T13:15:29.051016+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/connection.py", line 603, in connect 2023-03-12T13:15:29.051016+00:00 app[web.1]: await self.retry.call_with_retry( 2023-03-12T13:15:29.051016+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/retry.py", line 59, in call_with_retry 2023-03-12T13:15:29.051017+00:00 app[web.1]: return await do() 2023-03-12T13:15:29.051017+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/connection.py", line 640, in _connect 2023-03-12T13:15:29.051017+00:00 app[web.1]: reader, writer = await asyncio.open_connection( 2023-03-12T13:15:29.051018+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/asyncio/streams.py", line 52, in open_connection 2023-03-12T13:15:29.051019+00:00 app[web.1]: transport, _ = await loop.create_connection( 2023-03-12T13:15:29.051019+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/asyncio/base_events.py", line 1090, in create_connection 2023-03-12T13:15:29.051019+00:00 app[web.1]: transport, protocol = await self._create_connection_transport( 2023-03-12T13:15:29.051019+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/asyncio/base_events.py", line 1120, in _create_connection_transport 2023-03-12T13:15:29.051020+00:00 app[web.1]: await waiter 2023-03-12T13:15:29.051020+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/asyncio/sslproto.py", line 534, in data_received 2023-03-12T13:15:29.051020+00:00 app[web.1]: ssldata, appdata = self._sslpipe.feed_ssldata(data) 2023-03-12T13:15:29.051020+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/asyncio/sslproto.py", line 188, in feed_ssldata 2023-03-12T13:15:29.051021+00:00 app[web.1]: self._sslobj.do_handshake() 2023-03-12T13:15:29.051021+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/ssl.py", line 945, in do_handshake 2023-03-12T13:15:29.051021+00:00 app[web.1]: self._sslobj.do_handshake() 2023-03-12T13:15:29.051021+00:00 app[web.1]: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain (_ssl.c:1129) 2023-03-12T13:15:29.051021+00:00 app[web.1]: 2023-03-12T13:15:29.051022+00:00 app[web.1]: During handling of the above exception, another exception occurred: 2023-03-12T13:15:29.051022+00:00 app[web.1]: 2023-03-12T13:15:29.051022+00:00 app[web.1]: Traceback (most recent call last): 2023-03-12T13:15:29.051022+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/routing.py", line 62, in __call__ 2023-03-12T13:15:29.051022+00:00 app[web.1]: return await application(scope, receive, send) 2023-03-12T13:15:29.051023+00:00 app[web.1]: File "/app/hawlak/notifications/channelsmiddleware.py", line 23, in __call__ 2023-03-12T13:15:29.051023+00:00 app[web.1]: return await super().__call__(scope, receive, send) 2023-03-12T13:15:29.051023+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/middleware.py", line 24, in __call__ 2023-03-12T13:15:29.051023+00:00 app[web.1]: return await self.inner(scope, receive, send) 2023-03-12T13:15:29.051023+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/routing.py", line 116, in __call__ 2023-03-12T13:15:29.051023+00:00 app[web.1]: return await application( 2023-03-12T13:15:29.051023+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/consumer.py", line 94, in app 2023-03-12T13:15:29.051024+00:00 app[web.1]: return await consumer(scope, receive, send) 2023-03-12T13:15:29.051024+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/consumer.py", line 58, in __call__ 2023-03-12T13:15:29.051024+00:00 app[web.1]: await await_many_dispatch( 2023-03-12T13:15:29.051024+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/utils.py", line 50, in await_many_dispatch 2023-03-12T13:15:29.051024+00:00 app[web.1]: await dispatch(result) 2023-03-12T13:15:29.051024+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/consumer.py", line 73, in dispatch 2023-03-12T13:15:29.051024+00:00 app[web.1]: await handler(message) 2023-03-12T13:15:29.051025+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels/generic/websocket.py", line 173, in websocket_connect 2023-03-12T13:15:29.051025+00:00 app[web.1]: await self.connect() 2023-03-12T13:15:29.051025+00:00 app[web.1]: File "/app/hawlak/notifications/consumers.py", line 9, in connect 2023-03-12T13:15:29.051025+00:00 app[web.1]: await self.channel_layer.group_add( 2023-03-12T13:15:29.051025+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/channels_redis/core.py", line 523, in group_add 2023-03-12T13:15:29.051025+00:00 app[web.1]: await connection.zadd(group_key, {channel: time.time()}) 2023-03-12T13:15:29.051026+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/client.py", line 509, in execute_command 2023-03-12T13:15:29.051026+00:00 app[web.1]: conn = self.connection or await pool.get_connection(command_name, **options) 2023-03-12T13:15:29.051026+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/connection.py", line 1400, in get_connection 2023-03-12T13:15:29.051026+00:00 app[web.1]: await connection.connect() 2023-03-12T13:15:29.051026+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.9/site-packages/redis/asyncio/connection.py", line 611, in connect 2023-03-12T13:15:29.051026+00:00 app[web.1]: raise ConnectionError(self._error_message(e)) 2023-03-12T13:15:29.051027+00:00 app[web.1]: redis.exceptions.ConnectionError: Error 1 connecting to ec2-50-17-163-82.compute-1.amazonaws.com:7550. 1. 2023-03-12T13:15:29.052221+00:00 app[web.1]: 10.1.17.28:21462 - - [12/Mar/2023:13:15:29] "WSDISCONNECT /ws/notification/" - -
I tried a a solution to provide the hosts as a dict in the like this and I had a function the parse the url and returns its component but that solved the problem of "idna" encode of the URL but still can't connect
from urllib.parse import urlparse
def parse_redis_url(url):
""" parses a redis url into component parts, stripping password from the host.
Long keys in the url result in parsing errors, since labels within a hostname
cannot exceed 64 characters under
idna rules.
In that event, we remove the key/password so that it can be passed
separately to the RedisChannelLayer.
Heroku REDIS_URL does not include the DB number, so we allow for a default value of '0'
"""
parsed = urlparse(url)
parts = parsed.netloc.split(':')
host = ':'.join(parts[0:-1])
port = parts[-1]
path = parsed.path.split('/')[1:]
db = int(path[0]) if len(path) >= 1 else 0
user, password = (None, None)
if '@' in host:
creds, host = host.split('@')
user, password = creds.split(':')
host = f'{user}@{host}'
return host, port, user, password, db
channels layers
REDIS_URL = env('REDIS_URL', default='redis://localhost:6379')
REDIS_HOST, REDIS_PORT, REDIS_USER, REDIS_PASSWORD, REDIS_DB = parse_redis_url(REDIS_URL)
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [{
'address': f'{env("REDIS_PROTOCOL")}://{REDIS_HOST}:{REDIS_PORT}',
'db': REDIS_DB,
'password': REDIS_PASSWORD,
}],
},
},
}
I also tried several approaches from Heroku docs and django chanels docs but never managed to make it work.