Reputation: 762
I am using Tornado 2.4, and I am trying to integrate async call.
Lets say I need to access to a remote resource through a HTTP call, so I made this function in a tornado.web.RequestHandler
:
@tornado.web.asynchronous
def get(self, *args):
try:
self.remote_call()
return 'OK'
except Exception, e:
self.handle_exception(e)
@gen.engine
def remote_call(self):
http_client = httpclient.AsyncHTTPClient()
response = yield gen.Task(http_client.fetch, 'http://google.com')
self.process(response)
So my problem is, since remote_call
is yielding a Task
, it will obviously exit the remote_call
function and continue the get function. Then when my task is complete, the engine will process the response.
But if an error happen in the self.process(response)
, it will not be catch by my except, since this part of the code is not actually called here, but inside the engine where I do have no control.
So my question is, can I have some control on this engine? Can I handle error, can I ask to perform some specific task at the end the function?
I could do this directly in the function like this
@tornado.web.asynchronous
def get(self, *args):
self.remote_call()
return 'OK'
@gen.engine
def remote_call(self):
http_client = httpclient.AsyncHTTPClient()
response = yield gen.Task(http_client.fetch, 'http://google.com')
try:
self.process(response)
except:
self.handle_exception(e)
But I want to make the handle exception generic and not copy pasting this on every of my Handler.
So do I have a way to access to the engine of Tornado? Note that I am using Tornado 2.4 but I can migrate to 3.0 if needed. Thanks
Upvotes: 2
Views: 994
Reputation: 94961
You can handle it in 2.4 by decorating your get
call with @gen.engine
, wrapping the call to self.remote_call
in a gen.Task
, and then yield
ing from that:
@tornado.web.asynchronous
@gen.engine
def get(self, *args):
try:
yield gen.Task(self.remote_call)
except Exception, e:
self.handle_exception(e)
self.finish() # Make sure you call this when `get` is asynchronous.
@gen.engine
def remote_call(self):
http_client = httpclient.AsyncHTTPClient()
response = yield gen.Task(http_client.fetch, 'http://google.com')
self.process(response)
This will allow you to handle the exception in get
, though you'll still see a traceback from the exception being raise in remote_call
.
However, I highly recommend you upgrade. Tornado is now on version 4.0. With 3.0 or later, you can use gen.coroutine
instead of gen.engine
and web.asynchronous
:
@gen.coroutine
def get(self, *args):
try:
yield self.remote_call()
except Exception, e:
self.handle_exception(e)
self.finish()
@gen.coroutine
def remote_call(self):
http_client = httpclient.AsyncHTTPClient()
response = yield http_client.fetch('http://google.com')
self.process(response)
coroutine
properly supresses the traceback from any exception thrown in remote_call
, as well as letting you handle it in get
.
Upvotes: 4
Reputation: 762
Ok thanks it works. I had to do this however:
@tornado.web.asynchronous
@gen.engine
def get(self, *args):
try:
yield gen.Task(lambda cb: self.remote_call())
except Exception, e:
self.handle_exception(e)
self.finish() # Make sure you call this when `get` is asynchronous.
@gen.engine
def remote_call(self):
http_client = httpclient.AsyncHTTPClient()
response = yield gen.Task(http_client.fetch, 'http://google.com')
self.process(response)
Upvotes: 1