def retry(func, retry_classes=None, fail_classes=None, exc_callback=None, backoff_delay=BACKOFF_DELAY):
 if (fail_classes and retry_classes and set(fail_classes).intersection(retry_classes)):
  raise ValueError("Can't include exception classes in both fail_on and retry_on")
 def should_retry_on(exc):
  if (fail_classes and isinstance(exc, tuple(fail_classes))):
   return False
  if (retry_classes and (not isinstance(exc, tuple(retry_classes)))):
   return False
  return True
 @functools.wraps(func)
 def wrapped(*args, **kwargs):
  while True:
   try:
    return func(*args, **kwargs)
   except gevent.GreenletExit as e:
    raise
   except Exception as e:
    if (not should_retry_on(e)):
     raise
    if (exc_callback is not None):
     exc_callback(e)
   gevent.sleep((backoff_delay + int(random.uniform(1, 10))))
 return wrapped

def retry ( func , retry_classes = None , fail_classes = None , exc_callback = None , backoff_delay = BACKOFF_DELAY ) : if ( fail_classes and retry_classes and set ( fail_classes ) . intersection ( retry_classes ) ) : raise ValueError ( "Can't include exception classes in both fail_on and retry_on" ) def should_retry_on ( exc ) : if ( fail_classes and isinstance ( exc , tuple ( fail_classes ) ) ) : return False if ( retry_classes and ( not isinstance ( exc , tuple ( retry_classes ) ) ) ) : return False return True @ functools . wraps ( func ) def wrapped ( * args , ** kwargs ) : while True : try : return func ( * args , ** kwargs ) except gevent . GreenletExit as e : raise except Exception as e : if ( not should_retry_on ( e ) ) : raise if ( exc_callback is not None ) : exc_callback ( e ) gevent . sleep ( ( backoff_delay + int ( random . uniform ( 1 , 10 ) ) ) ) return wrapped
retry calling the decorated function using an exponential backoff .