web-dev-qa-db-fra.com

Django 3.1: streaminghttPesponse avec un générateur asynchreux

Documentation pour Django 3.1 en dit sur ASYNC Vues:

Les principaux avantages sont la possibilité de servir des centaines de connexions sans utiliser Python======= Ceci vous permet d'utiliser des types de diffusion lente, d'interrogation longue et d'autres types de réponses passionnantes.

Je crois que "streaming lent" signifie que nous pourrions mettre en œuvre un [~ # ~ # ~] SSE [~ # ~] Vue sans monopoliser un fil par client, alors j'ai essayé d'esquisser une vue simple, comme si:

async def stream(request):

    async def event_stream():
        while True:
            yield 'data: The server time is: %s\n\n' % datetime.datetime.now()
            await asyncio.sleep(1)

    return StreamingHttpResponse(event_stream(), content_type='text/event-stream')

(Remarque: j'ai adapté le code de cette réponse )

Malheureusement, lorsque cette vue est invoquée, elle soulève l'exception suivante:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/asgiref/sync.py", line 330, in thread_handler
    raise exc_info[1]
  File "/usr/local/lib/python3.7/site-packages/Django/core/handlers/exception.py", line 38, in inner
    response = await get_response(request)
  File "/usr/local/lib/python3.7/site-packages/Django/core/handlers/base.py", line 231, in _get_response_async
    response = await wrapped_callback(request, *callback_args, **callback_kwargs)
  File "./chat/views.py", line 144, in watch
    return StreamingHttpResponse(event_stream(), content_type='text/event-stream')
  File "/usr/local/lib/python3.7/site-packages/Django/http/response.py", line 367, in __init__
    self.streaming_content = streaming_content
  File "/usr/local/lib/python3.7/site-packages/Django/http/response.py", line 382, in streaming_content
    self._set_streaming_content(value)
  File "/usr/local/lib/python3.7/site-packages/Django/http/response.py", line 386, in _set_streaming_content
    self._iterator = iter(value)
TypeError: 'async_generator' object is not iterable

Pour moi, cela montre que StreamingHttpResponse _ ne supporte actuellement pas les générateurs ASYNC.

J'ai essayé de modifier StreamingHttpResponse pour utiliser async for Mais je n'ai pas pu faire grand chose.

Une idée de la façon dont je pouvais faire ça?

12
Benoit Blanchon

Une autre façon de faire SSE est d'utiliser une bibliothèque spéciale Django-eventstream :

Ajouter une suite à la page HTML qui consommera des données:

<script src="{% static 'Django_eventstream/eventsource.min.js' %}"></script>
<script src="{% static 'Django_eventstream/reconnecting-eventsource.js' %}"></script>

var es = new ReconnectingEventSource('/events/');

es.addEventListener('message', function (e) {
    console.log(e.data);
}, false);

es.addEventListener('stream-reset', function (e) {
    // ... client fell behind, reinitialize ...
}, false);

Pour le backend, vous aurez besoin de correctement configurez django , et plus tard, vous pourrez appeler la méthode suivante dans n'importe quelle vue/tâche/signal/méthode nécessaire à l'événement côté serveur (SSE):

Ajouter une vue à la suite qui produira des données (événements):

# from Django_eventstream import send_event

send_event('test', 'message', {'text': 'hello world'})
0
wowkin2