import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

10
python/redo/PKG-INFO Normal file
View file

@ -0,0 +1,10 @@
Metadata-Version: 1.0
Name: redo
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

4
python/redo/README Normal file
View file

@ -0,0 +1,4 @@
Redo - Utilities to retry Python callables
******************************************
Redo provides various means to add seamless retriability to any Python callable. Redo includes a plain function (redo.retry), a decorator (redo.retriable), and a context manager (redo.retrying) to enable you to integrate it in the best possible way for your project. As a bonus, a standalone interface is also included ("retry"). For details and sample invocations have a look at the docstrings in redo/__init__.py.

View file

@ -0,0 +1,240 @@
# ***** BEGIN LICENSE BLOCK *****
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# ***** END LICENSE BLOCK *****
import time
from functools import wraps
from contextlib import contextmanager
import logging
import random
log = logging.getLogger(__name__)
def retrier(attempts=5, sleeptime=10, max_sleeptime=300, sleepscale=1.5, jitter=1):
"""
A generator function that sleeps between retries, handles exponential
backoff and jitter. The action you are retrying is meant to run after
retrier yields.
At each iteration, we sleep for sleeptime + random.randint(-jitter, jitter).
Afterwards sleeptime is multiplied by sleepscale for the next iteration.
Args:
attempts (int): maximum number of times to try; defaults to 5
sleeptime (float): how many seconds to sleep between tries; defaults to
60s (one minute)
max_sleeptime (float): the longest we'll sleep, in seconds; defaults to
300s (five minutes)
sleepscale (float): how much to multiply the sleep time by each
iteration; defaults to 1.5
jitter (int): random jitter to introduce to sleep time each iteration.
the amount is chosen at random between [-jitter, +jitter]
defaults to 1
Yields:
None, a maximum of `attempts` number of times
Example:
>>> n = 0
>>> for _ in retrier(sleeptime=0, jitter=0):
... if n == 3:
... # We did the thing!
... break
... n += 1
>>> n
3
>>> n = 0
>>> for _ in retrier(sleeptime=0, jitter=0):
... if n == 6:
... # We did the thing!
... break
... n += 1
... else:
... 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 sleeptime_real
if jitter:
sleeptime_real = sleeptime + random.randint(-jitter, jitter)
# our jitter should scale along with the sleeptime
jitter = int(jitter * sleepscale)
else:
sleeptime_real = sleeptime
sleeptime *= sleepscale
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.
Args:
action (callable): the function to retry
attempts (int): maximum number of times to try; defaults to 5
sleeptime (float): how many seconds to sleep between tries; defaults to
60s (one minute)
max_sleeptime (float): the longest we'll sleep, in seconds; defaults to
300s (five minutes)
sleepscale (float): how much to multiply the sleep time by each
iteration; defaults to 1.5
jitter (int): random jitter to introduce to sleep time each iteration.
the amount is chosen at random between [-jitter, +jitter]
defaults to 1
retry_exceptions (tuple): tuple of exceptions to be caught. If other
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
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)
... 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:
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_name)
raise
continue
finally:
n += 1
def retriable(*retry_args, **retry_kwargs):
"""
A decorator factory for retry(). Wrap your function in @retriable(...) to
give it retry powers!
Arguments:
Same as for `retry`, with the exception of `action`, `args`, and `kwargs`,
which are left to the normal function definition.
Returns:
A function decorator
Example:
>>> count = 0
>>> @retriable(sleeptime=0, jitter=0)
... def foo():
... global count
... count += 1
... print(count)
... if count < 3:
... raise ValueError("count too small")
... return "success!"
>>> foo()
1
2
3
'success!'
"""
def _retriable_factory(func):
@wraps(func)
def _retriable_wrapper(*args, **kwargs):
return retry(func, args=args, kwargs=kwargs, *retry_args,
**retry_kwargs)
return _retriable_wrapper
return _retriable_factory
@contextmanager
def retrying(func, *retry_args, **retry_kwargs):
"""
A context manager for wrapping functions with retry functionality.
Arguments:
func (callable): the function to wrap
other arguments as per `retry`
Returns:
A context manager that returns retriable(func) on __enter__
Example:
>>> count = 0
>>> def foo():
... global count
... count += 1
... 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
'success!'
"""
yield retriable(*retry_args, **retry_kwargs)(func)

53
python/redo/redo/cmd.py Normal file
View file

@ -0,0 +1,53 @@
# ***** BEGIN LICENSE BLOCK *****
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
# ***** END LICENSE BLOCK *****
import logging
from subprocess import check_call, CalledProcessError
import sys
from redo import retrying
log = logging.getLogger(__name__)
def main():
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument(
"-a", "--attempts", type=int, default=5,
help="How many times to retry.")
parser.add_argument(
"-s", "--sleeptime", type=int, default=60,
help="How long to sleep between attempts. Sleeptime doubles after each attempt.")
parser.add_argument(
"-m", "--max-sleeptime", type=int, default=5*60,
help="Maximum length of time to sleep between attempts (limits backoff length).")
parser.add_argument("-v", "--verbose", action="store_true", default=False)
parser.add_argument("cmd", nargs="+", help="Command to run. Eg: wget http://blah")
args = parser.parse_args()
if args.verbose:
logging.basicConfig(level=logging.INFO)
logging.getLogger("retry").setLevel(logging.INFO)
else:
logging.basicConfig(level=logging.ERROR)
logging.getLogger("retry").setLevel(logging.ERROR)
try:
with retrying(check_call, attempts=args.attempts, sleeptime=args.sleeptime,
max_sleeptime=args.max_sleeptime,
retry_exceptions=(CalledProcessError,)) as r_check_call:
r_check_call(args.cmd)
except KeyboardInterrupt:
sys.exit(-1)
except Exception as e:
log.error("Unable to run command after %d attempts" % args.attempts, exc_info=True)
rc = getattr(e, "returncode", -2)
sys.exit(rc)
if __name__ == "__main__":
main()

8
python/redo/setup.cfg Normal file
View file

@ -0,0 +1,8 @@
[wheel]
universal = 1
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

18
python/redo/setup.py Normal file
View file

@ -0,0 +1,18 @@
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
setup(
name="redo",
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",
)