简体   繁体   English

Gevent:重试greenlet一次

[英]Gevent: Retry greenlet once

I'm doing a few dozen HTTP requests inside a Gevent pool. 我在Gevent池中做了几十个HTTP请求。

The goal is to retry a request once if it failed, but only once. 目标是在失败时重试一次请求,但只返回一次。 Otherwise, it should throw an exception. 否则,它应该抛出异常。

How would I write gevent code with at pool that supports re-running HTTP requests once if they fail? 如果它们失败,我将如何在支持重新运行HTTP请求的池中编写gevent代码?

Could this approach work? 这种方法有用吗?

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)
  • Ist there a cleaner way to obtain the argument of the greenlet function than via exception arguments? 我有一个更清晰的方法来获取greenlet函数的参数而不是通过异常参数吗?
  • Is there a possibility that the joinall(greenlets) methods returns after an exception occurs inside do_request but before the retry_once event handler is called? 有没有一种可能性,即joinall(greenlets)内发生异常后返回方法do_request但之前retry_once事件处理程序被调用?
  • Is there a cleaner way to restart a greenlet with the same arguments, so I wouldn't need the is_retry kwarg at spawn_greenlet ? 有没有更简洁的方法来重新启动具有相同参数的greenlet,所以我不需要is_retry is_retry spawn_greenlet
  • As far as I understand this, gevent.joinall(greenlets) only joins the greenlets returned by map. 据我所知, gevent.joinall(greenlets)只加入map返回的greenlets。 When there's an exception, is the original greenlet replaced with the new one returned by retry_once ? 当出现异常时,是否将原始greenlet替换为retry_once返回的新retry_once If not, does processing continue even though the additional greenlets are still running? 如果没有,即使其他greenlet仍在运行,处理是否仍在继续? How could I wait for all greenlets to finish in that case? 在这种情况下,我怎么能等待所有的greenlets完成?

Gevent docs are very scarce and there seem to be no other resources in the web documenting this, even though this is a fairly common use case. Gevent文档非常稀缺,网络中似乎没有其他资源记录这一点,即使这是一个相当常见的用例。 Therefore I don't consider this a too localized question. 因此,我不认为这是一个太局部化的问题。

Don't use spawn/link/link_exception for retrying things. 不要使用spawn / link / link_exception来重试。 Just use normal Python: 只需使用普通的Python:

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

Also, gevent.pool.Pool.map automatically spawns greenlet within given pool, you don't have to do it. 此外,gevent.pool.Pool.map会自动在给定池中生成greenlet,您不必这样做。

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

Now, you only need to implement do_something() , which can be normal Python/requests code: 现在,您只需要实现do_something() ,它可以是普通的Python /请求代码:

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

Have fun! 玩得开心!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM