I tried to make a chat app with django-channels
.
But a RuntimeError occurs when I create a new django-chanels
project and edit data in the admin site.
I'm not sure that I think the error occurred because I made several django-channels
projects.
When I built my first project, WebSocket is not working, so I made another 2nd, 3rd, 4th project with django-channels
. Now WebSocket is connected, but I have trouble with RuntimeError (Error message: Single thread executor already being user, would deadlock)
What can I do to fix this?
myproject/settings.py
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-is!$&voe3y058!2sus9egmxh@d!$)=l&o8_vl=m8zz!ap+d#a#"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"users.apps.UsersConfig",
"channels",
"core.apps.CoreConfig",
"broadcasts.apps.BroadcastsConfig",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "busker.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "busker.wsgi.application"
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
ASGI_APPLICATION = "busker.asgi.application"
CHANNEL_LAYERS = {"default": {"BACKEND": "channels.layers.InMemoryChannelLayer"}}
AUTH_USER_MODEL = "users.User"
myproject/asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
import broadcasts.routing
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = ProtocolTypeRouter(
{
"http": get_asgi_application(),
# Just HTTP for now. (We can add other protocols later.)
"websocket": AuthMiddlewareStack(
URLRouter(broadcasts.routing.websocket_urlpatterns)
),
}
)
myapp/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_group_name = "Test-Room"
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
print("Disconnected!")
async def receive(self, text_data):
receive_dict = json.loads(text_data)
message = receive_dict["message"]
await self.channel_layer.group_send(
self.room_group_name, {"type": "send.message", "message": message}
)
async def send_message(self, event):
message = event["message"]
await self.send(text_data=json.dumps({"message": message}))
myapp/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r"", consumers.ChatConsumer.as_asgi()),
]
Try pip install 'asgiref==3.3.4'
.
I noticed a similar RuntimeError: Single thread executor already being used, would deadlock
after upgrading from asgiref
3.3.4 to 3.4.1.
This appears to be due to a currently unresolved issue in channels
3.0.4 where concurrent requests on the Django development server are intermittently failing. See also Runtime Error Deadlock occurring randomly in Django.
In 3.4.0, asgiref
introduced additional deadlock checks. That's a good thing, but may have exposed an underlying issue in channels. From the changelog:
* Calling sync_to_async directly from inside itself (which causes a deadlock
when in the default, thread-sensitive mode) now has deadlock detection.
If you do need to install asgiref >= 3.4.1, a workaround in development is to use python manage.py runserver --noasgi
. This also has the benefit of being a little faster to reload.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With