mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
10
python/redo/PKG-INFO
Normal file
10
python/redo/PKG-INFO
Normal 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
4
python/redo/README
Normal 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.
|
||||
240
python/redo/redo/__init__.py
Normal file
240
python/redo/redo/__init__.py
Normal 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
53
python/redo/redo/cmd.py
Normal 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
8
python/redo/setup.cfg
Normal 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
18
python/redo/setup.py
Normal 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",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue