La respuesta HTTP de transmisión de tornado como AsyncHTTPClient recibe fragmentos

Estoy intentando escribir un controlador de solicitud de tornado que realiza solicitudes HTTP asíncronas y devuelve datos al cliente a medida que lo recibe de sus solicitudes asíncronas. Desafortunadamente, no puedo hacer que Tornado devuelva ningún dato al cliente hasta que se hayan completado todas las solicitudes HTTP Async.

A continuación se muestra una demostración de mi controlador de solicitudes.

 clase StreamingHandler (web.RequestHandler):

     all_requested = False
     peticiones = []

     @ web.asynchronous
     def get (self):

         http_client = httpclient.AsyncHTTPClient ()
         self.write ('algo de apertura')

         big_request = httpclient.HTTPRequest (url = '[some_big_request]', streaming_callback = self.on_chunk)
         small_request = httpclient.HTTPRequest (url = '[some_small_request]', streaming_callback = self.on_chunk)

         self.requests.append (http_client.fetch (big_request, callback = self.on_response_complete))
         self.requests.append (http_client.fetch (small_request, callback = self.on_response_complete))

         self.all_requested = True

     def on_chunk (self, chunk):
         self.write ('alguna parte')
         auto.flush ()

     def on_response_complete (auto, respuesta):
         si es self.all_requested y all (request.done () para solicitar en self.requests):
             self.write ('algo de cierre')
             auto. terminar ()

Espero que una solicitud GET a este controlador devuelva inicialmente el texto ‘algo de apertura’, luego devuelva rápidamente ‘algo de trozo’ para la solicitud pequeña, y luego devuelva ‘algo de trozo’ (potencialmente varias veces) para la solicitud más grande, antes Finalmente devolviendo ‘algún cierre’, y cerrando la conexión. En su lugar, después de establecer la conexión, el cliente espera unos segundos a que se completen todas las solicitudes y, a continuación, recibe toda la Respuesta HTTP a la vez, antes de cerrar.

¿Cómo haría para obtener mi comportamiento deseado de Tornado?

¡Gracias por adelantado!

Decora tu método con gen.coroutine y gen.coroutine una lista de futuros. Aquí hay un ejemplo simple:

 from tornado import gen, web, httpclient class StreamingHandler(web.RequestHandler): @web.asynchronous @gen.coroutine def get(self): client = httpclient.AsyncHTTPClient() self.write('some opening') self.flush() requests = [ httpclient.HTTPRequest( url='http://httpbin.org/delay/' + str(delay), streaming_callback=self.on_chunk ) for delay in [5, 4, 3, 2, 1] ] # `map()` doesn't return a list in Python 3 yield list(map(client.fetch, requests)) self.write('some closing') self.finish() def on_chunk(self, chunk): self.write('some chunk') self.flush() 

Tenga en cuenta que aunque las solicitudes se devuelven “hacia atrás”, la primera parte se recibirá después de aproximadamente un segundo. Si los enviaste de forma sincrónica, tardarías 15 segundos. Cuando los solicitas de forma asíncrona, te lleva solo 5.