AsyncJsonWebsocketConsumer inheritor class can't be used in await expression
Mikael-Caetano opened this issue · comments
I am upgrading my django channels application, which was previously using channels 2.4.0 to channels 4.0.0. But I am receiving the following exception when trying to connect to my consumer through websocket:
ds-chat-chat-1 | System check identified no issues (0 silenced).
ds-chat-chat-1 | August 03, 2023 - 12:28:10
ds-chat-chat-1 | Django version 4.1.10, using settings 'chat.settings'
ds-chat-chat-1 | Starting ASGI/Daphne version 4.0.0 development server at http://0.0.0.0:8080/
ds-chat-chat-1 | Quit the server with CONTROL-C.
ds-chat-chat-1 | WebSocket HANDSHAKING /gws [172.23.0.1:51638]
ds-chat-chat-1 | Exception inside application: object ChatConsumer can't be used in 'await' expression
ds-chat-chat-1 | Traceback (most recent call last):
ds-chat-chat-1 | File "/usr/local/lib/python3.10/site-packages/django/contrib/staticfiles/handlers.py", line 101, in __call__
ds-chat-chat-1 | return await self.application(scope, receive, send)
ds-chat-chat-1 | File "/usr/local/lib/python3.10/site-packages/channels/routing.py", line 62, in __call__
ds-chat-chat-1 | return await application(scope, receive, send)
ds-chat-chat-1 | File "/usr/local/lib/python3.10/site-packages/channels/sessions.py", line 47, in __call__
ds-chat-chat-1 | return await self.inner(dict(scope, cookies=cookies), receive, send)
ds-chat-chat-1 | File "/usr/local/lib/python3.10/site-packages/channels/sessions.py", line 263, in __call__
ds-chat-chat-1 | return await self.inner(wrapper.scope, receive, wrapper.send)
ds-chat-chat-1 | File "/usr/local/lib/python3.10/site-packages/channels/routing.py", line 116, in __call__
ds-chat-chat-1 | return await application(
ds-chat-chat-1 | TypeError: object ChatConsumer can't be used in 'await' expression
ds-chat-chat-1 | WebSocket DISCONNECT /gws [172.23.0.1:51638]
What I did for updating was to obviously update the libraries in my requirements.txt:
boto3==1.27.0
channels==4.0.0
channels-redis==4.1.0
daphne==4.0.0
Django==4.1.10
django-redis==5.3.0
django-cors-headers==3.14.0
django-filter==23.2
djangorestframework==3.14.0
dj-database-url==2.0.0
django-storages==1.13.2
drf-yasg==1.21.6
Markdown==3.2.1
mutagen==1.45.1
mysqlclient==2.1.1
python-decouple
pytz
redis==4.6.0
sentry-sdk==1.27.0
uwsgi
Include daphne in my installed apps, right above "django.contrib.staticfiles".
And include the "http" key in my application:
routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.sessions import SessionMiddlewareStack
from django.core.asgi import get_asgi_application
from chat.apps.core import routing as core_routing
application = ProtocolTypeRouter(
{
"http": get_asgi_application(),
"websocket": SessionMiddlewareStack(
URLRouter(core_routing.websocket_urlpatterns)
),
}
)
asgi.py:
"""
ASGI config for ChatAPI project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""
import os
import django
from channels.routing import get_default_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "chat.settings")
django.setup()
application = get_default_application()
channels settings:
ASGI_APPLICATION = "chat.routing.application"
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [config("REDIS_URL")],
"capacity": 1500,
# "expiry": 10,
},
}
}
consumers.py:
from __future__ import unicode_literals
import datetime
import json
from urllib import parse
from channels.db import database_sync_to_async
from channels.generic.websocket import (
AsyncJsonWebsocketConsumer,
AsyncWebsocketConsumer,
)
from .models import UserCompany
# Returns user by validating Token
class TokenAuth(AsyncWebsocketConsumer):
@database_sync_to_async
def get_user(self):
scope = self.scope
try:
# Parse the scope and gets the token
query = parse.parse_qs(scope["query_string"].decode("utf-8"))[
"token"
][0]
if query:
token = UserCompany.objects.get(key=query)
# Returns token user
return token.key
return None
except:
return None
class ChatConsumer(AsyncJsonWebsocketConsumer, TokenAuth):
async def connect(self):
# connect room
key_ = await self.get_user()
self.group_name = str(key_)
await self.channel_layer.group_add(self.group_name, self.channel_name)
try:
await self.update_user_status(self.group_name, True)
except:
pass
await self.accept()
async def disconnect(self, _):
# Leave room group
try:
await self.update_user_status(self.group_name, False)
except:
pass
await self.channel_layer.group_discard(
self.group_name, self.channel_name
)
Any ideas?
If you couldn't solve your problem, check your routers:
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r"ws/chat/(?P<room_name>\w+)/$", consumers.ChatConsumer.as_asgi()),
]
The as_asgi()
method should be used.
https://channels.readthedocs.io/en/latest/tutorial/part_2.html