Python Django Channels выдает ошибку при запуске на компьютере коллег, но не на моем компьютере, что идет не так?
Я столкнулся со следующей ошибкой.
Странность этой ошибки в том, что она не возникает на моем компьютере с windows 11, а возникает только на компьютере windows 11 коллеги и на удаленном сервере debian linux, который я установил специально для того, чтобы проверить, будет ли подобная ошибка возникать и в Linux.
На всех компьютерах одинаковый код (git синхронизирован), одинаковые библиотеки (pip freeze и venv), одинаковая версия python (кроме linux-сервера)
Я не могу выяснить происхождение и не могу найти никакой информации о подобной ошибке на StackOverflow или любом другом сайте. Самое странное, что это работает на моем собственном компьютере!
Traceback (most recent call last):
File "/usr/lib/python3.11/threading.py", line 1038, in _bootstrap_inner
self.run()
File "/usr/lib/python3.11/threading.py", line 975, in run
self._target(*self._args, **self._kwargs)
File "/srv/<redacted>/venv/lib/python3.11/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/srv/<redacted>/venv/lib/python3.11/site-packages/daphne/management/commands/runserver.py", line 128, in inner_run
application=self.get_application(options),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/srv/<redacted>/venv/lib/python3.11/site-packages/daphne/management/commands/runserver.py", line 153, in get_application
return ASGIStaticFilesHandler(get_default_application())
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/srv/<redacted>/venv/lib/python3.11/site-packages/daphne/management/commands/runserver.py", line 31, in get_default_application
raise ImproperlyConfigured("Cannot import ASGI_APPLICATION module %r" % path)
django.core.exceptions.ImproperlyConfigured: Cannot import ASGI_APPLICATION module 'config.asgi'
Эта ошибка очень бесполезна, поэтому после дополнительной отладки мы выяснили, что причиной сбоя является:
ImportError: cannot import name 'DEFAULT_CHANNEL_LAYER' from 'channels'
Мой компьютер: Windows 11 - Python 3.12.1 (работает здесь)
Мой коллега: Windows 11 - Python 3.12.1 (здесь не работает)
Сервер Linux (текущая трассировка): Debian - Python 3.11.2 (здесь тоже не работает)
Вероятно, это не связано с несоответствием версии python, потому что у моего коллеги тоже есть такая проблема, и он использует ту же версию, что и я.
Я хотел бы добавить, что используемые каналы django - это относительно чистая установка. Поэтому я считаю, что проблема заключается в настройке. Мы также используем Django Rest Framework, Django Tenants & Django Tenant User в качестве основных библиотек.
Ошибка возникает только при использовании ASGI-сервера daphne вместо стандартного WSGI, и он падает только при импорте потребителя, в противном случае он не падает.
Релевантный код:
asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.core.asgi import get_asgi_application
from django.urls import path
from config.middleware import TokenAuthMiddleware
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
from apps.chats.consumers import MyWebSocketConsumer
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": TokenAuthMiddleware(
URLRouter(
[
path("ws/test/", MyWebSocketConsumer.as_asgi()),
]
)
),
})
config/middleware.py
from django.contrib.auth.models import AnonymousUser
from rest_framework.authtoken.models import Token
from channels.db import database_sync_to_async
from channels.middleware import BaseMiddleware
@database_sync_to_async
def get_user(token_key):
try:
token = Token.objects.get(key=token_key)
return token.user
except Token.DoesNotExist:
return AnonymousUser()
class TokenAuthMiddleware(BaseMiddleware):
def __init__(self, inner):
super().__init__(inner)
async def __call__(self, scope, receive, send):
try:
token_key = dict(scope['headers']).get(b'authorization').decode('ascii').split(" ")[1]
except ValueError:
token_key = None
print("test3")
print(token_key)
scope['user'] = AnonymousUser() if token_key is None else await get_user(token_key)
return await super().__call__(scope, receive, send)
apps/chats/consumers.py
import json
from channels.generic.websocket import JsonWebsocketConsumer
from django_tenants.utils import get_tenant_model
from apps.public.models import Domain
from django_tenants.utils import tenant_context
Tenant = get_tenant_model()
class MyWebSocketConsumer(JsonWebsocketConsumer):
def connect(self):
user = self.scope['user']
tenant_domain = dict(self.scope['headers']).get(b'host').decode('ascii').split(":")[0]
tenant_domain_obj = Domain.objects.get(domain=tenant_domain)
tenant = Tenant.objects.filter(domains=tenant_domain_obj).first()
with tenant_context(tenant):
if user.is_authenticated:
user_chats = user.chats_followed.all()
self.groups = [f"chat_{chat.id}" for chat in user_chats]
# Subscribe the WebSocket connection to all the user's chat groups
for group_name in self.groups:
self.channel_layer.group_add(group_name, self.channel_name)
# Accept the WebSocket connection
self.accept()
def disconnect(self, close_code):
# Remove the WebSocket connection from the group
for group_name in self.groups:
self.channel_layer.group_discard(group_name, self.channel_name)
def receive_json(self, content):
# This is called when a message is received from the client
message = content.get("message", "")
chat_id = content.get("chat_id")
print(message)
# Broadcast the message to the specific chat group
if chat_id:
group_name = f"chat_{chat_id}"
self.channel_layer.group_send(
group_name,
{
"type": "chat_message",
"chat_id": chat_id,
"message": message,
}
)
def chat_message(self, event):
message = event['message']
# Send the message to the WebSocket
self.send(text_data=json.dumps({"message": message}))
Я сам в полном недоумении, почему на моем компьютере она работает, а на чужом - нет.
- Я проверил переменные окружения (они в порядке)
- Я проверил версию python
- Я проверил установленные пакеты
- Я проверил версии ОС
все одно и то же, что идет не так.