Bug 1301785: update python/redo to 1.6; r=gps
authorDustin J. Mitchell <dustin@mozilla.com>
Mon, 31 Oct 2016 15:41:28 +0000
changeset 346993 7053f12766bc5b21ef76e495b550b0413ca70a80
parent 346992 a352e8d4b5d92451341bc0bd36d840cda5e11c76
child 346994 dadc7a4494eccaaf561113a8c1850900a62a0f58
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1301785
milestone52.0a1
Bug 1301785: update python/redo to 1.6; r=gps MozReview-Commit-ID: BdSQshy2f0p
python/redo/PKG-INFO
python/redo/redo.egg-info/PKG-INFO
python/redo/redo.egg-info/SOURCES.txt
python/redo/redo/__init__.py
python/redo/setup.cfg
python/redo/setup.py
--- a/python/redo/PKG-INFO
+++ b/python/redo/PKG-INFO
@@ -1,10 +1,10 @@
 Metadata-Version: 1.0
 Name: redo
-Version: 1.4
+Version: 1.6
 Summary: Utilities to retry Python callables.
 Home-page: https://github.com/bhearsum/redo
 Author: Ben Hearsum
 Author-email: ben@hearsum.ca
 License: UNKNOWN
 Description: UNKNOWN
 Platform: UNKNOWN
--- a/python/redo/redo.egg-info/PKG-INFO
+++ b/python/redo/redo.egg-info/PKG-INFO
@@ -1,10 +1,10 @@
 Metadata-Version: 1.0
 Name: redo
-Version: 1.4
+Version: 1.6
 Summary: Utilities to retry Python callables.
 Home-page: https://github.com/bhearsum/redo
 Author: Ben Hearsum
 Author-email: ben@hearsum.ca
 License: UNKNOWN
 Description: UNKNOWN
 Platform: UNKNOWN
--- a/python/redo/redo.egg-info/SOURCES.txt
+++ b/python/redo/redo.egg-info/SOURCES.txt
@@ -1,9 +1,10 @@
-README
+setup.cfg
 setup.py
 redo/__init__.py
 redo/cmd.py
 redo.egg-info/PKG-INFO
 redo.egg-info/SOURCES.txt
 redo.egg-info/dependency_links.txt
 redo.egg-info/entry_points.txt
+redo.egg-info/pbr.json
 redo.egg-info/top_level.txt
\ No newline at end of file
--- a/python/redo/redo/__init__.py
+++ b/python/redo/redo/__init__.py
@@ -48,34 +48,46 @@ def retrier(attempts=5, sleeptime=10, ma
 
         >>> n = 0
         >>> for _ in retrier(sleeptime=0, jitter=0):
         ...     if n == 6:
         ...         # We did the thing!
         ...         break
         ...     n += 1
         ... else:
-        ...     print "max tries hit"
+        ...     print("max tries hit")
         max tries hit
     """
+    jitter = jitter or 0  # py35 barfs on the next line if jitter is None
+    if jitter > sleeptime:
+        # To prevent negative sleep times
+        raise Exception('jitter ({}) must be less than sleep time ({})'.format(jitter, sleeptime))
+
+    sleeptime_real = sleeptime
     for _ in range(attempts):
         log.debug("attempt %i/%i", _ + 1, attempts)
-        yield
+
+        yield sleeptime_real
+
         if jitter:
-            sleeptime += random.randint(-jitter, jitter)
-            sleeptime = max(sleeptime, 0)
+            sleeptime_real = sleeptime + random.randint(-jitter, jitter)
+            # our jitter should scale along with the sleeptime
+            jitter = int(jitter * sleepscale)
+        else:
+            sleeptime_real = sleeptime
 
-        if _ == attempts - 1:
-            # Don't need to sleep the last time
-            break
-        log.debug("sleeping for %.2fs (attempt %i/%i)", sleeptime, _ + 1, attempts)
-        time.sleep(sleeptime)
         sleeptime *= sleepscale
-        if sleeptime > max_sleeptime:
-            sleeptime = max_sleeptime
+
+        if sleeptime_real > max_sleeptime:
+            sleeptime_real = max_sleeptime
+
+        # Don't need to sleep the last time
+        if _ < attempts - 1:
+            log.debug("sleeping for %.2fs (attempt %i/%i)", sleeptime_real, _ + 1, attempts)
+            time.sleep(sleeptime_real)
 
 
 def retry(action, attempts=5, sleeptime=60, max_sleeptime=5 * 60,
           sleepscale=1.5, jitter=1, retry_exceptions=(Exception,),
           cleanup=None, args=(), kwargs={}):
     """
     Calls an action function until it succeeds, or we give up.
 
@@ -95,60 +107,70 @@ def retry(action, attempts=5, sleeptime=
                                   exceptions are raised by action(), then these
                                   are immediately re-raised to the caller.
         cleanup (callable): optional; called if one of `retry_exceptions` is
                             caught. No arguments are passed to the cleanup
                             function; if your cleanup requires arguments,
                             consider using functools.partial or a lambda
                             function.
         args (tuple): positional arguments to call `action` with
-        hwargs (dict): keyword arguments to call `action` with
+        kwargs (dict): keyword arguments to call `action` with
 
     Returns:
         Whatever action(*args, **kwargs) returns
 
     Raises:
         Whatever action(*args, **kwargs) raises. `retry_exceptions` are caught
         up until the last attempt, in which case they are re-raised.
 
     Example:
         >>> count = 0
         >>> def foo():
         ...     global count
         ...     count += 1
-        ...     print count
+        ...     print(count)
         ...     if count < 3:
         ...         raise ValueError("count is too small!")
         ...     return "success!"
         >>> retry(foo, sleeptime=0, jitter=0)
         1
         2
         3
         'success!'
     """
     assert callable(action)
     assert not cleanup or callable(cleanup)
+
+    action_name = getattr(action, '__name__', action)
+    if args or kwargs:
+        log_attempt_format = ("retry: calling %s with args: %s,"
+                              " kwargs: %s, attempt #%%d"
+                              % (action_name, args, kwargs))
+    else:
+        log_attempt_format = ("retry: calling %s, attempt #%%d"
+                              % action_name)
+
     if max_sleeptime < sleeptime:
         log.debug("max_sleeptime %d less than sleeptime %d" % (
             max_sleeptime, sleeptime))
 
     n = 1
     for _ in retrier(attempts=attempts, sleeptime=sleeptime,
                      max_sleeptime=max_sleeptime, sleepscale=sleepscale,
                      jitter=jitter):
         try:
-            log.info("retry: Calling %s with args: %s, kwargs: %s, "
-                     "attempt #%d" % (action, str(args), str(kwargs), n))
+            logfn = log.info if n != 1 else log.debug
+            logfn(log_attempt_format, n)
             return action(*args, **kwargs)
         except retry_exceptions:
             log.debug("retry: Caught exception: ", exc_info=True)
             if cleanup:
                 cleanup()
             if n == attempts:
-                log.info("retry: Giving up on %s" % action)
+                log.info("retry: Giving up on %s" % action_name)
                 raise
             continue
         finally:
             n += 1
 
 
 def retriable(*retry_args, **retry_kwargs):
     """
@@ -163,17 +185,17 @@ def retriable(*retry_args, **retry_kwarg
         A function decorator
 
     Example:
         >>> count = 0
         >>> @retriable(sleeptime=0, jitter=0)
         ... def foo():
         ...     global count
         ...     count += 1
-        ...     print count
+        ...     print(count)
         ...     if count < 3:
         ...         raise ValueError("count too small")
         ...     return "success!"
         >>> foo()
         1
         2
         3
         'success!'
@@ -199,17 +221,17 @@ def retrying(func, *retry_args, **retry_
     Returns:
         A context manager that returns retriable(func) on __enter__
 
     Example:
         >>> count = 0
         >>> def foo():
         ...     global count
         ...     count += 1
-        ...     print count
+        ...     print(count)
         ...     if count < 3:
         ...         raise ValueError("count too small")
         ...     return "success!"
         >>> with retrying(foo, sleeptime=0, jitter=0) as f:
         ...     f()
         1
         2
         3
--- a/python/redo/setup.cfg
+++ b/python/redo/setup.cfg
@@ -1,5 +1,8 @@
+[wheel]
+universal = 1
+
 [egg_info]
 tag_build = 
 tag_date = 0
 tag_svn_revision = 0
 
--- a/python/redo/setup.py
+++ b/python/redo/setup.py
@@ -1,13 +1,17 @@
-from setuptools import setup
+try:
+    from setuptools import setup
+except ImportError:
+    from distutils.core import setup
+
 
 setup(
     name="redo",
-    version="1.4",
+    version="1.6",
     description="Utilities to retry Python callables.",
     author="Ben Hearsum",
     author_email="ben@hearsum.ca",
     packages=["redo"],
     entry_points={
         "console_scripts": ["retry = redo.cmd:main"],
     },
     url="https://github.com/bhearsum/redo",