def staggered_retries(run, *a, **kw):
    """
    A version of spawn that will block will it is done
    running the function, and which will call the function
    repeatedly as time progresses through the timeouts list.

    Best used for idempotent network calls (e.g. HTTP GETs).

    e.g.::

        user_data = async.staggered_retries(get_data, max_results,
                                            latent_data_ok, public_credential_load,
                                            timeouts_secs=[0.1, 0.5, 1, 2])

    returns None on timeout.
    """
    ctx = context.get_context()
    ready = gevent.event.Event()
    ready.clear()

    def callback(source):
        if source.successful():
            ready.set()

    if kw in 'timeouts_secs':
        timeouts_secs = kw.pop('timeouts_secs')
    else:
        timeouts_secs = [0.05, 0.1, 0.15, 0.2]
    if timeouts_secs[0] > 0:
        timeouts_secs.insert(0, 0)
    gs = gevent.spawn(run, *a, **kw)
    gs.link_value(callback)
    running = [gs]
    for i in range(1, len(timeouts_secs)):
        this_timeout = timeouts_secs[i] - timeouts_secs[i - 1]
        if ctx.dev:
            this_timeout = this_timeout * 5.0
        ml.ld2("Using timeout {0}", this_timeout)
        try:
            with gevent.Timeout(this_timeout):
                ready.wait()
                break
        except gevent.Timeout:
            ml.ld2("Timed out!")
            log_rec = ctx.log.critical('ASYNC.STAGGER', run.__name__)
            log_rec.failure('timed out after {timeout}',
                            timeout=this_timeout)
            gs = gevent.spawn(run, *a, **kw)
            gs.link_value(callback)
            running.append(gs)
    vals = [l.value for l in running if l.successful()]
    for g in running:
        g.kill()
    if vals:
        return vals[0]
    else:
        return None
dataset/ETHPy150Open paypal/support/support/async.py/staggered_retries/swapped operands of `in`