z0r
z0r

Reputation: 8585

Anything special required to use Tornado's data_received method without blocking?

I have a POST request handler that takes streaming data as input and writes it to AWS APIs. The data is sent to AWS using multiple inner requests, which are made via boto3. I believe boto3 is blocking but may release the GIL when doing I/O: it seems to use urllib3.connection internally. So I wrapped it in a call to run_in_executor - something like this cut-down code:

@stream_request_body
class Handler(RequestHandler):
    async def prepare(self):
        self.parser = BufferedParser()

    async def data_received(self, chunk):
        complete_part = self.parser.receive(chunk)
        if complete_part:
            await IOLoop.current().run_in_executor(
                None, self.send_via_boto, complete_part)

    async def post(self):
        self.set_header('Content-Type', 'text/plain')
        self.write("OK")

My question is: will the awaited call to send_via_boto block the client from uploading the next chunk? Do I need to implement something fancier, or should this already be non-blocking?

Upvotes: 0

Views: 504

Answers (1)

Fine
Fine

Reputation: 2154

"block the client from uploading the next chunk" — a client uploads data not to your app directly, but to a TCP socket. That socket has a certain size, i.e. buffer, so if buffer is full, client will wait until it's emptied and then continue upload. Your app, with the help of Tornado, reads from this TCP-socket-buffer and empty it with the part that was read. The process of sending a chunk to AWS won't stop the client from uploading the data to TCP socket, even if you send data to AWS in a blocking way (i.e. without run_in_executor, but you will block your server from serving other requests). If you send data to AWS slower than client uploads, then your app would be bottleneck and will prevent (which is technically not the same as blocking) a client from uploading more.

Upvotes: 1

Related Questions