Gevent:重试greenlet一次

时间:2012-12-21 15:27:12

标签: python concurrency gevent

我在Gevent池中做了几十个HTTP请求。

目标是在失败时重试一次请求,但只返回一次。否则,它应该抛出异常。

我如何在支持重新运行HTTP请求的池中编写gevent代码,如果它们失败了?

这种方法有用吗?

import requests
import gevent
from gevent.pool import Pool

pool = Pool(10)

def do_request(id):
    r = requests.get('http://example.com/%u' % id)
    if not r.status_code == 200:
        raise RuntimeError(id)

def spawn_greenlet(id, is_retry=False):
    if not is_retry:
        g = gevent.spawn(id)
        g.link_exception(retry_once)
    else:
        g = pool.spawn(id)
        g.link_exception(raise_exception)
    return g

def retry_once(greenlet):
    return spawn_greenlet(greenlet.exception.args[0])

def raise_exception(greenlet):
    if greenlet.exception:
        raise greenlet.exception
    raise RuntimeError('Unknown error in greenlet processing.')


greenlets = pool.map(spawn_greenlet, [1, 2, 3, 4, 5])
gevent.joinall(greenlets)
  • 我是否有更简洁的方法来获取greenlet函数的参数而不是通过异常参数?
  • joinall(greenlets)内但在调用do_request事件处理程序之前发生异常后,retry_once方法是否有可能返回?
  • 是否有更简洁的方法可以使用相同的参数重新启动greenlet,因此我不需要is_retry处的spawn_greenlet kwarg?
  • 据我了解,gevent.joinall(greenlets)只加入地图返回的greenlets。如果有异常,原始greenlet是否被retry_once返回的新greenlet替换?如果没有,即使其他greenlet仍在运行,处理是否仍在继续?在这种情况下,我怎么能等待所有的greenlets完成?

Gevent文档非常稀缺,网络上似乎没有其他资源记录这一点,即使这是一个相当常见的用例。因此,我不认为这是一个太局部化的问题。

1 个答案:

答案 0 :(得分:1)

不要使用spawn / link / link_exception来重试。只需使用普通的Python:

def do_something_with_retry(*args):
    try:
      return do_something(*args)
    except Exception:
      return do_something(*args)

此外,gevent.pool.Pool.map会自动在给定池中生成greenlet,您不必这样做。

pool = Pool(10)
pool.map(do_something_with_retry, [1, 2, 3])

现在,您只需要实现do_something(),这可以是普通的Python /请求代码:

def do_something(*args):
    return requests.get('http://gevent.org')

玩得开心!