Skip to content
Snippets Groups Projects
Commit c7e846a9 authored by Piotr Maślanka's avatar Piotr Maślanka
Browse files

**bugfix**: `ExponentialBackoff` will start

    available
parent b3b3780f
No related branches found
No related tags found
No related merge requests found
...@@ -4,3 +4,6 @@ ...@@ -4,3 +4,6 @@
`terminate_on` won't be swallowed anymore. `terminate_on` won't be swallowed anymore.
* added support for `terminate_on` to `IntervalTerminableThread` * added support for `terminate_on` to `IntervalTerminableThread`
and `CPUTimeAwareIntervalTerminableThread` and `CPUTimeAwareIntervalTerminableThread`
* added `grace_amount` to `ExponentialBackoff`
* **bugfix**: `ExponentialBackoff` will start
available
__version__ = '2.17.11a2' __version__ = '2.17.11a3'
...@@ -33,14 +33,19 @@ class ExponentialBackoff: ...@@ -33,14 +33,19 @@ class ExponentialBackoff:
:param limit: maximum sleep timeout :param limit: maximum sleep timeout
:param sleep_fun: function used to sleep. Will accept a single argument - number of :param sleep_fun: function used to sleep. Will accept a single argument - number of
seconds to wait seconds to wait
:param grace_amount: amount of fails() that this will survive before everything fails
""" """
__slots__ = 'start', 'limit', 'counter', 'sleep_fun', 'unavailable_until', 'condition' __slots__ = 'start', 'limit', 'counter', 'sleep_fun', 'unavailable_until', 'condition', \
'grace_amount', 'grace_counter'
def __init__(self, start: float = 1, limit: float = 30, def __init__(self, start: float = 1, limit: float = 30,
sleep_fun: tp.Callable[[float], None] = time.sleep): sleep_fun: tp.Callable[[float], None] = time.sleep,
grace_amount: int = 0):
self.start = start self.start = start
self.grace_amount = grace_amount
self.grace_counter = 0
self.limit = limit self.limit = limit
self.counter = start self.counter = 0
self.sleep_fun = sleep_fun self.sleep_fun = sleep_fun
self.condition = Condition() self.condition = Condition()
self.unavailable_until = None self.unavailable_until = None
...@@ -55,11 +60,14 @@ class ExponentialBackoff: ...@@ -55,11 +60,14 @@ class ExponentialBackoff:
""" """
Called when something fails. Called when something fails.
""" """
if self.counter == 0: if self.grace_amount == self.grace_counter:
self.counter = self.start if self.counter == 0:
self.counter = self.start
else:
self.counter = min(self.limit, self.counter * 2)
self.unavailable_until = time.monotonic() + self.counter
else: else:
self.counter = min(self.limit, self.counter * 2) self.grace_counter += 1
self.unavailable_until = time.monotonic() + self.counter
def wait_until_available(self, timeout: tp.Optional[float] = None) -> None: def wait_until_available(self, timeout: tp.Optional[float] = None) -> None:
""" """
...@@ -113,5 +121,6 @@ class ExponentialBackoff: ...@@ -113,5 +121,6 @@ class ExponentialBackoff:
Called when something successes. Called when something successes.
""" """
self.counter = 0 self.counter = 0
self.grace_counter = 0
self.unavailable_until = None self.unavailable_until = None
self.condition.notify_all() self.condition.notify_all()
...@@ -13,6 +13,16 @@ from concurrent.futures import Future ...@@ -13,6 +13,16 @@ from concurrent.futures import Future
class TestTime(unittest.TestCase): class TestTime(unittest.TestCase):
def test_exponential_backoff_grace(self):
eb = ExponentialBackoff(grace_amount=2)
self.assertTrue(eb.available)
eb.failed()
self.assertTrue(eb.available)
eb.failed()
self.assertTrue(eb.available)
eb.failed()
self.assertFalse(eb.available)
def test_exponential_backoff_earlier_wakeup(self): def test_exponential_backoff_earlier_wakeup(self):
eb = ExponentialBackoff(start=5, limit=30) eb = ExponentialBackoff(start=5, limit=30)
...@@ -62,7 +72,7 @@ class TestTime(unittest.TestCase): ...@@ -62,7 +72,7 @@ class TestTime(unittest.TestCase):
eb.sleep() eb.sleep()
eb.failed() eb.failed()
eb.sleep() eb.sleep()
self.assertGreaterEqual(measurement(), 2+4) self.assertGreaterEqual(measurement(), 3)
def test_measure(self): def test_measure(self):
with measure(timeout=0.5) as measurement: with measure(timeout=0.5) as measurement:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment