Add backoff.py.

This commit is contained in:
Ethan Dalool 2020-10-06 11:18:25 -07:00
parent 1a0b71673f
commit 0202aeaca0

88
voussoirkit/backoff.py Normal file
View 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
'''