Add backoff.py.
This commit is contained in:
parent
1a0b71673f
commit
0202aeaca0
1 changed files with 88 additions and 0 deletions
88
voussoirkit/backoff.py
Normal file
88
voussoirkit/backoff.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
'''
|
||||||
|
The Backoff classes are intended to be used to control `time.sleep` with
|
||||||
|
varying backoff strategies.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
bo = backoff.Linear(m=1, b=1, max=30)
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
something()
|
||||||
|
except Exception:
|
||||||
|
time.sleep(bo.next())
|
||||||
|
else:
|
||||||
|
bo.reset()
|
||||||
|
|
||||||
|
If you want to add random fuzziness to your sleeps, that should be done on the
|
||||||
|
calling end. For example, `bo.next() + (random.random() - 0.5)`.
|
||||||
|
'''
|
||||||
|
class Backoff:
|
||||||
|
def __init__(self, max):
|
||||||
|
if max is None:
|
||||||
|
pass
|
||||||
|
elif max <= 0:
|
||||||
|
raise ValueError(f'max must be positive, not {max}.')
|
||||||
|
self.max = max
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
y = self._calc()
|
||||||
|
if self.max is not None:
|
||||||
|
y = min(y, self.max)
|
||||||
|
self.x += 1
|
||||||
|
return y
|
||||||
|
|
||||||
|
def rewind(self, steps):
|
||||||
|
self.x = max(0, self.x - steps)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.x = 0
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
|
||||||
|
class Exponential(Backoff):
|
||||||
|
'''
|
||||||
|
Exponential backoff produces next = (a**x) + b.
|
||||||
|
'''
|
||||||
|
def __init__(self, a, b, *, max):
|
||||||
|
super().__init__(max)
|
||||||
|
self.x = 0
|
||||||
|
self.a = a
|
||||||
|
self.b = b
|
||||||
|
self.max = max
|
||||||
|
|
||||||
|
def _calc(self):
|
||||||
|
return (self.a ** self.x) + self.b
|
||||||
|
|
||||||
|
class Linear(Backoff):
|
||||||
|
'''
|
||||||
|
Linear backoff produces next = (m * x) + b.
|
||||||
|
'''
|
||||||
|
def __init__(self, m, b, *, max):
|
||||||
|
super().__init__(max)
|
||||||
|
self.x = 0
|
||||||
|
self.m = m
|
||||||
|
self.b = b
|
||||||
|
self.max = max
|
||||||
|
|
||||||
|
def _calc(self):
|
||||||
|
return (self.m * self.x) + self.b
|
||||||
|
|
||||||
|
class Quadratic(Backoff):
|
||||||
|
'''
|
||||||
|
Quadratic backoff produces next = (a * x**2) + (b * x) + c.
|
||||||
|
'''
|
||||||
|
def __init__(self, a, b, c, *, max):
|
||||||
|
super().__init__(max)
|
||||||
|
self.x = 0
|
||||||
|
self.a = a
|
||||||
|
self.b = b
|
||||||
|
self.c = c
|
||||||
|
self.max = max
|
||||||
|
|
||||||
|
def _calc(self):
|
||||||
|
return (self.a * self.x**2) + (self.b * self.x) + self.c
|
||||||
|
|
||||||
|
'''
|
||||||
|
people are backing off
|
||||||
|
you'll get used to it
|
||||||
|
'''
|
Loading…
Reference in a new issue