diff --git a/lifecycle/gunicorn.conf.py b/lifecycle/gunicorn.conf.py index b8ea3fcec..f9ba639f7 100644 --- a/lifecycle/gunicorn.conf.py +++ b/lifecycle/gunicorn.conf.py @@ -1,4 +1,5 @@ """Gunicorn config""" +import os import warnings from multiprocessing import cpu_count from pathlib import Path @@ -14,6 +15,8 @@ worker_class = "uvicorn.workers.UvicornWorker" # Docker containers don't have /tmp as tmpfs worker_tmp_dir = "/dev/shm" +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "passbook.root.settings") + logconfig_dict = { "version": 1, "disable_existing_loggers": False, diff --git a/passbook/lib/sentry.py b/passbook/lib/sentry.py index dfaceed8a..598eb7a69 100644 --- a/passbook/lib/sentry.py +++ b/passbook/lib/sentry.py @@ -1,5 +1,5 @@ """passbook sentry integration""" -from aioredis.errors import ReplyError +from aioredis.errors import ReplyError, ConnectionClosedError from billiard.exceptions import WorkerLostError from botocore.client import ClientError from celery.exceptions import CeleryError @@ -40,6 +40,7 @@ def before_send(event, hint): RedisError, ResponseError, ReplyError, + ConnectionClosedError, # websocket errors ChannelFull, WebSocketException, diff --git a/passbook/root/asgi.py b/passbook/root/asgi.py index 92b235b1a..29099f0bf 100644 --- a/passbook/root/asgi.py +++ b/passbook/root/asgi.py @@ -6,19 +6,21 @@ 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 typing from time import time from typing import Any, ByteString, Dict import django from asgiref.compatibility import guarantee_single_callable +from channels.routing import ProtocolTypeRouter, URLRouter from defusedxml import defuse_stdlib from django.core.asgi import get_asgi_application from sentry_sdk.integrations.asgi import SentryAsgiMiddleware from structlog import get_logger -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "passbook.root.settings") +from passbook.root import websocket + +# DJANGO_SETTINGS_MODULE is set in gunicorn.conf.py defuse_stdlib() django.setup() @@ -129,5 +131,14 @@ class ASGILogger: application = ASGILogger( - guarantee_single_callable(SentryAsgiMiddleware(get_asgi_application())) + guarantee_single_callable( + SentryAsgiMiddleware( + ProtocolTypeRouter( + { + "http": get_asgi_application(), + "websocket": URLRouter(websocket.websocket_urlpatterns), + } + ) + ) + ) ) diff --git a/passbook/root/routing.py b/passbook/root/routing.py deleted file mode 100644 index 8cdeeed39..000000000 --- a/passbook/root/routing.py +++ /dev/null @@ -1,14 +0,0 @@ -"""root Websocket URLS""" -from channels.routing import ProtocolTypeRouter, URLRouter -from django.urls import path - -from passbook.outposts.channels import OutpostConsumer - -application = ProtocolTypeRouter( - { - # (http->django views is added by default) - "websocket": URLRouter( - [path("ws/outpost//", OutpostConsumer.as_asgi())] - ), - } -) diff --git a/passbook/root/settings.py b/passbook/root/settings.py index 279a18343..c3d7c5547 100644 --- a/passbook/root/settings.py +++ b/passbook/root/settings.py @@ -208,7 +208,7 @@ TEMPLATES = [ }, ] -ASGI_APPLICATION = "passbook.root.routing.application" +ASGI_APPLICATION = "passbook.root.asgi.application" CHANNEL_LAYERS = { "default": { diff --git a/passbook/root/websocket.py b/passbook/root/websocket.py new file mode 100644 index 000000000..005de97f1 --- /dev/null +++ b/passbook/root/websocket.py @@ -0,0 +1,6 @@ +"""root Websocket URLS""" +from django.urls import path + +from passbook.outposts.channels import OutpostConsumer + +websocket_urlpatterns = [path("ws/outpost//", OutpostConsumer.as_asgi())]