Lvxiuquan
Lvxiuquan

Reputation: 59

tornado, make on_finish() asynchronous

override method on_finish(). Decorate this method with .gen.coroutine to make it asynchronous, it worked.

@gen.coroutine
def on_finish(self):
    print("==========on_finish==============")

but use async def to make it asynchronous, it failed.

async def on_finish(self):
    print("==========on_finish==============")

# RuntimeWarning: coroutine 'BaseHandler.on_finish' was never awaited

self.on_finish()

Why can't I use async def to make it asynchronous?

Upvotes: 5

Views: 961

Answers (1)

Ben Darnell
Ben Darnell

Reputation: 22134

Coroutines have a different interface than regular functions. When overriding a method, you should make it a coroutine (or not) according to its documentation. All overridable methods in Tornado that may be coroutines say so in their documentation, and on_finish is not one of them.

What happens if you use a coroutine when the superclass doesn't expect it? As you see, this depends on the kind of coroutine. @gen.coroutine is "self-starting", so the coroutine will start, but nothing will wait for it to finish, and if it raises an exception, there is nowhere for that exception to be caught (so it will just be logged by the IOLoop). async def coroutines do not start automatically, something must await them, so if you use one where the caller is not expecting a coroutine, nothing will happen.

If you need to use a coroutine from a method where this is not allowed, you need to decide who's going to wait on the coroutine and handle its exceptions. If you don't need to catch exceptions and can just leave them for the logs, you can use IOLoop.add_callback to explicitly give this responsibility to the IOLoop:

def on_finish(self):
    IOLoop.current().add_callback(self.on_finish_async)

async def on_finish_async(self):
    ...

Upvotes: 6

Related Questions