Настройте HTTP-веб через WSGI и Websocket через ASGI в одном приложении Heroku

У меня есть небольшой вопрос к профессионалам Heroku. Как вы работаете с вебсокетами (django-channels) и http web dynos вместе в Django приложении? Вот мой Procfile setup-web:

gunicorn my_proj.wsgi
worker: celery -A my_proj.celery_app worker 
websocket: daphne my_proj.asgi:application --port 8001 --bind 0.0.0.0 -v2

Я использую Gunicorn для обычных веб-программ и Celery для фоновых задач, и все это хорошо. Но часть websocket не работает вообще. Это отлично работает на локалке (проверено на postman), но после развертывания на heroku я пытаюсь вызвать эту конечную точку и вижу NO logs heroku logs -t -d websocket

Я использую Django-каналы с ASGI, следовательно, Daphne (также пробовал uvicorn), но он просто тупит. Покопавшись немного, я наткнулся на то, что Heroku не очень хорошо работает с несколькими портами. Не уверен, правильно ли я понял, но если да, то как мне заставить это работать? Я мог бы сделать и нижеприведенный вариант (который отлично работает!)

web: daphne logistics_service.asgi:application --port $PORT --bind 0.0.0.0 -v2
worker: celery -A logistics_service.celery_app worker

Но я бы не хотел переводить все на ASGI для основных веб-материалов.

У меня на уме два подхода:

  • Нужно ли мне использовать менеджер процессов типа Supervisor?
  • Или, может быть, создать отдельное приложение только для WebSockets в том же конвейере?

Как вы управляете этим на Heroku? Любые советы будут оценены по достоинству.

Вот как выглядят файлы -

asgi.py

django_asgi_app = get_asgi_application()
application = ProtocolTypeRouter({
    # "http": django_asgi_app, 
    "websocket": URLRouter([
        path(r"chat/<str:room_name>/", WSConsumer.as_asgi()), 
    ]) 
})

А вот класс WSConsumer является расширением AsyncWebsocketConsumer

from channels.generic.websocket import AsyncWebsocketConsumer

class WSConsumer(AsyncWebsocketConsumer):
   ...

Кроме того, вы заметите, что у нас есть только потребитель. Нет никакого рабочего/сервера. Это потому, что об этом можно позаботиться программно (в представлении) и не нужно выставлять конечную точку. В случае использования система будет отправлять WebSocket-уведомление пользователю приложения, а он будет просто его потреблять. Например,

from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync

def send_ws_notification(room_name, **kwargs):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(room_name, {"type": "notification", "data": kwargs})

Пробовал все (простой http+websocket) на asgi, который работает нормально, но, как я уже говорил, я не хочу использовать asgi для простых конечных точек http.

Я также пытался использовать Gunicorn (предполагая, что Daphne не очень хорошо поддерживается на Heroku), но безуспешно.

Уже посетил следующие темы, но и там нет ответа.

Django теперь работает с каналами ASGI + WSGI в Heroku

Героку Джанго, несколько веб-динозавров

Вернуться на верх