Home > Software engineering >  Channels django
Channels django

Time:08-24

I'm trying to get django channels to work with daphne, but I can't connect rooms, the app runs good,but whenever I run the app, and open a "room" websocket it automatically disconnects, it is worth mentioning that my site is running with HTTP and any help will be apreciated

2022-08-19T13:20:57.879758 00:00 app[worker.1]: conn = await self.create_conn(loop)
2022-08-19T13:20:57.879769 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 79, in create_conn
2022-08-19T13:20:57.879862 00:00 app[worker.1]: return await aioredis.create_redis_pool(**kwargs)
2022-08-19T13:20:57.879863 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/commands/__init__.py", line 188, in create_redis_pool
2022-08-19T13:20:57.879967 00:00 app[worker.1]: pool = await create_pool(address, db=db,
2022-08-19T13:20:57.879978 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/pool.py", line 58, in create_pool
2022-08-19T13:20:57.880062 00:00 app[worker.1]: await pool._fill_free(override_min=False)
2022-08-19T13:20:57.880073 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/pool.py", line 383, in _fill_free
2022-08-19T13:20:57.880224 00:00 app[worker.1]: conn = await self._create_new_connection(self._address)
2022-08-19T13:20:57.880233 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/connection.py", line 133, in create_connection
2022-08-19T13:20:57.880336 00:00 app[worker.1]: await conn.auth(password)
2022-08-19T13:20:57.880345 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/util.py", line 52, in wait_ok
2022-08-19T13:20:57.880426 00:00 app[worker.1]: res = await fut
2022-08-19T13:20:57.880437 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/connection.py", line 186, in _read_data
2022-08-19T13:20:57.880564 00:00 app[worker.1]: obj = await self._reader.readobj()
2022-08-19T13:20:57.880576 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/stream.py", line 102, in readobj
2022-08-19T13:20:57.880669 00:00 app[worker.1]: await self._wait_for_data('readobj')
2022-08-19T13:20:57.880680 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/asyncio/streams.py", line 502, in _wait_for_data
2022-08-19T13:20:57.880853 00:00 app[worker.1]: await self._waiter
2022-08-19T13:20:57.880863 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/asyncio/selector_events.py", line 854, in _read_ready__data_received
2022-08-19T13:20:57.881081 00:00 app[worker.1]: data = self._sock.recv(self.max_size)
2022-08-19T13:20:57.881108 00:00 app[worker.1]: ConnectionResetError: [Errno 104] Connection reset by peer
2022-08-19T13:20:58.216868 00:00 heroku[worker.1]: Process exited with status 1
2022-08-19T13:20:58.288781 00:00 heroku[worker.1]: State changed from up to crashed
2022-08-19T13:20:58.293098 00:00 heroku[worker.1]: State changed from crashed to starting
2022-08-19T13:21:01.803835 00:00 heroku[worker.1]: Starting process with command `python manage.py runworker channel_layer -v2`
2022-08-19T13:21:02.114989 00:00 app[web.1]: /app/templates/allauth
2022-08-19T13:21:02.115157 00:00 app[web.1]: 2022-08-19 13:21:02,115 INFO     Adding $DATABASE_URL to default DATABASE Django setting.
2022-08-19T13:21:02.115388 00:00 app[web.1]: 2022-08-19 13:21:02,115 INFO     Adding $DATABASE_URL to TEST default DATABASE Django setting.
2022-08-19T13:21:02.115464 00:00 app[web.1]: 2022-08-19 13:21:02,115 INFO     Applying Heroku Staticfiles configuration to Django settings.
2022-08-19T13:21:02.115620 00:00 app[web.1]: 2022-08-19 13:21:02,115 INFO     Applying Heroku ALLOWED_HOSTS configuration to Django settings.
2022-08-19T13:21:02.115673 00:00 app[web.1]: 2022-08-19 13:21:02,115 INFO     Applying Heroku logging configuration to Django settings.
2022-08-19T13:21:02.425949 00:00 heroku[worker.1]: State changed from starting to up
2022-08-19T13:21:02.756499 00:00 app[web.1]: 2022-08-19 09:21:02,756 INFO     Starting server at tcp:port=5104:interface=0.0.0.0
2022-08-19T13:21:02.757304 00:00 app[web.1]: 2022-08-19 09:21:02,757 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2022-08-19T13:21:02.757571 00:00 app[web.1]: 2022-08-19 09:21:02,757 INFO     Configuring endpoint tcp:port=5104:interface=0.0.0.0
2022-08-19T13:21:02.758238 00:00 app[web.1]: 2022-08-19 09:21:02,758 INFO     HTTPFactory starting on 5104
2022-08-19T13:21:02.758408 00:00 app[web.1]: 2022-08-19 09:21:02,758 INFO     Starting factory <daphne.http_protocol.HTTPFactory object at 0x7f77a0c83a60>
2022-08-19T13:21:02.758717 00:00 app[web.1]: 2022-08-19 09:21:02,758 INFO     Listening on TCP address 0.0.0.0:5104
2022-08-19T13:21:02.973963 00:00 heroku[web.1]: State changed from starting to up
2022-08-19T13:21:03.384499 00:00 app[worker.1]: /app/templates/allauth
2022-08-19T13:21:04.746745 00:00 app[worker.1]: Running worker for channels ['channel_layer']
2022-08-19T13:21:04.764414 00:00 app[worker.1]: Traceback (most recent call last):
2022-08-19T13:21:04.764421 00:00 app[worker.1]: File "/app/manage.py", line 22, in <module>
2022-08-19T13:21:04.764513 00:00 app[worker.1]: main()
2022-08-19T13:21:04.764513 00:00 app[worker.1]: File "/app/manage.py", line 18, in main
2022-08-19T13:21:04.764568 00:00 app[worker.1]: execute_from_command_line(sys.argv)
2022-08-19T13:21:04.764579 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
2022-08-19T13:21:04.764694 00:00 app[worker.1]: utility.execute()
2022-08-19T13:21:04.764704 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
2022-08-19T13:21:04.764832 00:00 app[worker.1]: self.fetch_command(subcommand).run_from_argv(self.argv)
2022-08-19T13:21:04.764834 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/base.py", line 414, in run_from_argv
2022-08-19T13:21:04.764947 00:00 app[worker.1]: self.execute(*args, **cmd_options)
2022-08-19T13:21:04.764949 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/django/core/management/base.py", line 460, in execute
2022-08-19T13:21:04.765045 00:00 app[worker.1]: output = self.handle(*args, **options)
2022-08-19T13:21:04.765046 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels/management/commands/runworker.py", line 46, in handle
2022-08-19T13:21:04.765109 00:00 app[worker.1]: worker.run()
2022-08-19T13:21:04.765110 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/asgiref/server.py", line 62, in run
2022-08-19T13:21:04.765175 00:00 app[worker.1]: event_loop.run_until_complete(self.handle())
2022-08-19T13:21:04.765184 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
2022-08-19T13:21:04.765320 00:00 app[worker.1]: return future.result()
2022-08-19T13:21:04.765323 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels/worker.py", line 30, in handle
2022-08-19T13:21:04.765378 00:00 app[worker.1]: [listener.result() for listener in listeners]
2022-08-19T13:21:04.765380 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels/worker.py", line 30, in <listcomp>
2022-08-19T13:21:04.765469 00:00 app[worker.1]: [listener.result() for listener in listeners]
2022-08-19T13:21:04.765469 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels/worker.py", line 37, in listener
2022-08-19T13:21:04.765487 00:00 app[worker.1]: message = await self.channel_layer.receive(channel)
2022-08-19T13:21:04.765490 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 520, in receive
2022-08-19T13:21:04.765609 00:00 app[worker.1]: return (await self.receive_single(channel))[1]
2022-08-19T13:21:04.765628 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 542, in receive_single
2022-08-19T13:21:04.765726 00:00 app[worker.1]: content = await self._brpop_with_clean(
2022-08-19T13:21:04.765734 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 375, in _brpop_with_clean
2022-08-19T13:21:04.765828 00:00 app[worker.1]: async with self.connection(index) as connection:
2022-08-19T13:21:04.765828 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 862, in __aenter__
2022-08-19T13:21:04.765975 00:00 app[worker.1]: self.conn = await self.pool.pop()
2022-08-19T13:21:04.765978 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 93, in pop
2022-08-19T13:21:04.766043 00:00 app[worker.1]: conn = await self.create_conn(loop)
2022-08-19T13:21:04.766043 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/channels_redis/core.py", line 79, in create_conn
2022-08-19T13:21:04.766101 00:00 app[worker.1]: return await aioredis.create_redis_pool(**kwargs)
2022-08-19T13:21:04.766103 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/commands/__init__.py", line 188, in create_redis_pool
2022-08-19T13:21:04.766176 00:00 app[worker.1]: pool = await create_pool(address, db=db,
2022-08-19T13:21:04.766184 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/pool.py", line 58, in create_pool
2022-08-19T13:21:04.766241 00:00 app[worker.1]: await pool._fill_free(override_min=False)
2022-08-19T13:21:04.766243 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/pool.py", line 383, in _fill_free
2022-08-19T13:21:04.766334 00:00 app[worker.1]: conn = await self._create_new_connection(self._address)
2022-08-19T13:21:04.766342 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/connection.py", line 133, in create_connection
2022-08-19T13:21:04.766428 00:00 app[worker.1]: await conn.auth(password)
2022-08-19T13:21:04.766430 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/util.py", line 52, in wait_ok
2022-08-19T13:21:04.766495 00:00 app[worker.1]: res = await fut
2022-08-19T13:21:04.766497 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/connection.py", line 186, in _read_data
2022-08-19T13:21:04.766564 00:00 app[worker.1]: obj = await self._reader.readobj()
2022-08-19T13:21:04.766573 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/site-packages/aioredis/stream.py", line 102, in readobj
2022-08-19T13:21:04.766631 00:00 app[worker.1]: await self._wait_for_data('readobj')
2022-08-19T13:21:04.766640 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/asyncio/streams.py", line 502, in _wait_for_data
2022-08-19T13:21:04.766749 00:00 app[worker.1]: await self._waiter
2022-08-19T13:21:04.766758 00:00 app[worker.1]: File "/app/.heroku/python/lib/python3.10/asyncio/selector_events.py", line 854, in _read_ready__data_received
2022-08-19T13:21:04.766911 00:00 app[worker.1]: data = self._sock.recv(self.max_size)
2022-08-19T13:21:04.766935 00:00 app[worker.1]: ConnectionResetError: [Errno 104] Connection reset by peer
2022-08-19T13:21:05.128856 00:00 heroku[worker.1]: Process exited with status 1
2022-08-19T13:21:05.218917 00:00 heroku[worker.1]: State changed from up to crashed

I have

Django==4.0.6

daphne==3.0.2

channels==3.0.5

My configurations

ASGI.PY

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from django.urls import path

import django

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myProject.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django.setup()
django_asgi_app = get_asgi_application()

from chat import consumers


application = ProtocolTypeRouter({
    # Django's ASGI application to handle traditional HTTP requests
    "http": django_asgi_app,

    # WebSocket chat handler
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                    path("ws/<str:room_name>/", consumers.ChatConsumer.as_asgi()),
            ])
        )
    ),
})

PROCFILE (daphne working)

web: daphne myProject.asgi:application --port $PORT --bind 0.0.0.0 -v2
web2: gunicorn myProject.wsgi --log-file -
worker: python manage.py runworker channel_layer -v2

SETTINGS

....
ASGI_APPLICATION = 'myProject.asgi.application'
# Channels
CHANNEL_LAYERS = {
    "default": {
         'BACKEND': 'channels_redis.core.RedisChannelLayer',
        "CONFIG": {
            "hosts": ["redis://:XXXXXXXXXXXeca8e639d8b1ca9617d708224c89641133e6191292a@XXXXXXXXX-25-163.compute-1.amazonaws.com:27320"]
        },

    },
}
....

CONSUMERS.PY

import json 


from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async

from django.contrib.auth.models import User

from .models import Message, Room

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name'] # url route {'args': (), 'kwargs': {'room_name': 'Yoru Room Name'}}
        self.room_group_name = 'chat_%s' % self.room_name #chat_my_room

        await self.channel_layer.group_add(
            self.room_group_name, # group
            self.channel_name # channel
            )
        
        await self.accept()
        

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name, # group
            self.channel_name # channel         
            )

    async def receive(self, text_data):
        data = json.loads(text_data) # load json package {"message":"","username":"","room":""}
        message = data['message']
        username = data['username']
        room = data['room']

        await self.save_message(username, room, message)

        await self.channel_layer.group_send(
            self.room_group_name,
            {
            'type' : 'chat_message',
            'message' : message,
            'username' : username,
            'room' : room,
            }
            )

    async def chat_message(self, event):
        message = event['message']
        username = event['username']
        room = event['room']

        await self.send(text_data=json.dumps({ # create json package {"message":"","username":"","room":""}
            'message' : message,
            'username' : username,
            'room' : room,
            }))

    @sync_to_async
    def save_message(self, username, room, message):
        user = User.objects.get(username=username)
        room = Room.objects.get(slug=room)

        Message.objects.create(user=user, room=room, content=message)

ROOM.HTML

{{ room.slug|json_script:"json-roomname" }}
{{request.user.username|json_script:"json-username"}}

<script>
  const roomName = JSON.parse(document.getElementById('json-roomname').textContent);
  const userName = JSON.parse(document.getElementById('json-username').textContent);
  

  const charSocket = new WebSocket(
      (window.location.protocol === 'https:' ? 'wss' : 'ws')   '://'
        window.location.host
        '/ws/'
        roomName
        '/'

    );

CodePudding user response:

I can see you hard coded the REDIS_URL in the CHANNEL_LAYER configuration.

If the REDIS instance you are using is from heroku add-ons, it's best you access it from the environment variable. You will want to do this because heroku add-ons credentials often change from time to time.

Read this Heroku docs on add-ons credentials changing here

It's worth mentioning that storing credentials externally is also a good practice. By doing so, you are following the twelve - factor app methodology.

Also the fact that you are running on http didn't cause the issue as you managed that well by using 'ws' protocol when running http (ref. the ternary operator in setting your websocket connection).

CodePudding user response:

According to @FAYEMI BOLUWATIFE's answer I changed my Channel layer and it worked!

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

    },
}
  • Related