Search code examples
python-3.xasynchronousasync-awaittornadopython-asyncio

Tornado - How to stop all asynchronous 'await's from on_connection_close


So I have an asynchronous request handler in Tornado, that awaits for some events, after what it writes something to the client and terminates.

Basically it's something like this :

async def post(self, request_url):
    await my_semaphore.acquire()
        try:
            with await my_redis_pool as redis:
                redis_value = await redis.brpop("my_value", timeout=very_long_timeout)
            self.write(value)
    finally:
        my_semaphore.release()
        print("The semaphore is released !")

Everything works fine, except for one thing : if the client terminates the connection, the handler continues to await on whatever event it was waiting.

I found on_connection_close is called when the client closes the connexion ; so what can I call from this function to "break" the main handler out from the awaits? Is there a way to raise something, similar to an exception?

    def on_connection_close(self):
        print("on_connection_close")
        # what could I do here to interrupt whatever the post() method is awaiting

I've tried to call a raise tornado.web.HTTPError(504) from on_connection_close, but it doesn't work. "on_connection_close" is displayed immediately, but "The semaphore is released !" is displayed only after very_long_timeout.

Thanks in advance!


Solution

  • You need to keep track of the future. And then in on_connection_close you can set an empty result on the future. This will move the coroutine forward.

    self.redis_value_future = redis.brpop("my_value", timeout=very_long_timeout)
    redis_value = await self.redis_value_future
    

    And then set an empty result like this:

    def on_connection_close(self):
        self.redis_value_future.set_result('')