使用龙卷风执行并行异步请求时捕获异常

Catching exception while doing parallel async request with tornado

在我的程序中,我正在对某些主机执行一些获取请求。问题是我无法正确捕获主机断开连接时抛出的异常。我正在使用 tornado 并且请求是异步的。 考虑以下代码:

   self.http_client = AsyncHTTPClient()

    try:
         responses = yield [self.http_client.fetch(theUrl) for theUrl in URLS]                                             
    except Exception as e:
         if (e[0] == 111) or (e[0] == 599):
               #Do something

当主机断开连接时,有时我能够捕捉到异常,但它仍然会被抛出。例如,我将此错误消息打印到我的日志文件中:

ERROR:tornado.application:Multiple exceptions in yield list
Traceback (most recent call last):
  File "/opt/felix-web-mon/env/lib/python2.7/site-packages/tornado/gen.py", line 828, in callback
    result_list.append(f.result())
  File "/opt/felix-web-mon/env/lib/python2.7/site-packages/tornado/concurrent.py", line 238, in result
    raise_exc_info(self._exc_info)
  File "<string>", line 3, in raise_exc_info
error: [Errno 111] Connection refused

尽管我在我的代码中处理了“111”异常,但它仍然被抛出。我怀疑这是因为我正在使用列表理解(我需要)。 如何在 except 块中捕获此“yield list”中的多个异常?你能帮帮我吗?

等待多个未来,通过简单地产生一个列表,将 "discard" 对任何错误的所有响应。您可以使用:

  • WaiterIterator - 这个的好处是当它到达时你就会得到结果。您不会等到所有 yield 请求都完成(尤其是最慢的请求)。
  • fetch中传递raise_error=False以抑制加注

看看,两者都有描述。

from tornado.gen import coroutine
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient

@coroutine
def main():
    URLS = [
        'http://amazon.com',
        'https://www.kernel.org/some404',
        'http://localhost:8787',  # connection refused
        'http://google.com'
    ]
    http_client = AsyncHTTPClient()

    responses = yield [http_client.fetch(theUrl, raise_error=False) for theUrl in URLS]
    for idx, r in enumerate(responses):
        print(URLS[idx])
        if 200 <= r.code <= 299:
            print('> ok')
        elif 300 <= r.code <= 399:
            print('> ok - redirect')
        elif 400 <= r.code <= 499:
            print('> client err: %s' % r.code)
        elif 500 <= r.code <= 598:
            print('> server err: %s' % r.code)
        elif r.code == 599:
            print('> 599 connection error or timedouted request')

        # or something like below
        #try:
        #    res = r.rethorw()
        #except Exception:
             # do something


IOLoop.instance().run_sync(main)