Настройте 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
Героку Джанго, несколько веб-динозавров