fanout / django-eventstream

Server-Sent Events for Django
MIT License
650 stars 85 forks source link

asgi + wsgi server: events not sent #47

Closed foucdeg closed 4 years ago

foucdeg commented 4 years ago

Hello,

I've set up an application with django_eventstream and it works fine running locally with ./manage.py runserver. When I build my application behind uwsgi (for the wsgi endpoints) and uvicorn (for the asgi endpoints) on two distinct ports, clients can connect to the event stream but don't receive any events.

I think I've narrowed down the issue: when a client connects to the asgi app, the listener get registered in the ListenerManager. But when the wsgi app sends an event, the ListenerManager reports that it has no listeners. Printing the ListenerManager in these cases shows that the wsgi app and the asgi app do not use the same ListenerManager:

<django_eventstream.consumers.ListenerManager object at 0x7f3e4ab136d0> <django_eventstream.consumers.ListenerManager object at 0x7ff74499d8e0>

So it's likely that I didn't understand how to serve my asgi + wsgi app in production.

This is how I serve my app:

  uvicorn passe_un_dessin.asgi:application --host 0.0.0.0 --port 9002 & \
  uwsgi --http :9001 --wsgi-file passe_un_dessin/wsgi.py --master --processes 4 --threads 2

passe_un_dessin.settings :

WSGI_APPLICATION = "passe_un_dessin.wsgi.application"
ASGI_APPLICATION = "passe_un_dessin.routing.application"

passe_un_dessin.asgi :

import os
import django
from channels.routing import get_default_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "passe_un_dessin.settings.prod")
django.setup()
application = get_default_application()

passe_un_dessin.routing :

from channels.routing import ProtocolTypeRouter, URLRouter
import core.routing

application = ProtocolTypeRouter({"http": URLRouter(core.routing.urlpatterns)})

core.routing:

import django_eventstream
from channels.http import AsgiHandler
from channels.routing import URLRouter
from django.conf.urls import url

urlpatterns = [
    url(r"^events/", URLRouter(django_eventstream.routing.urlpatterns),),
    url(r"", AsgiHandler),
]

I've installed channels and django-eventstream.

Can you see what I'm doing wrong?

foucdeg commented 4 years ago

The app works using just the ASGI server. I'll keep it like that for now.

jkarneges commented 4 years ago

Indeed, the issue is each ASGI process has an independent ListenerManager and processes don't talk to each other. This means sending from a separate process (whether ASGI, WSGI, management command, etc) will have no effect. For basic setups, a single ASGI process is the right way to go.

If you want to run multiple Django processes, you'll need to put a GRIP proxy in front of them such as Pushpin.

foucdeg commented 4 years ago

Thanks for explaining!