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

add ExponentialBackoff.launch

parent 6384ec69
No related branches found
No related tags found
No related merge requests found
......@@ -2,3 +2,4 @@
* added automatic enum parsing to satella's JSONEncoder
* Satella's JSON file handling will internally use Satella's JSONEncoder
* added ExponentialBackoff.launch
__version__ = '2.17.17a3'
__version__ = '2.17.17a4'
import time
import typing as tp
from satella.coding.decorators.decorators import wraps
from satella.coding.typing import ExceptionList
from satella.coding.concurrent.thread import Condition
from .measure import measure
from ..exceptions import WouldWaitMore
......@@ -124,3 +128,40 @@ class ExponentialBackoff:
self.grace_counter = 0
self.unavailable_until = None
self.condition.notify_all()
def launch(self, exceptions_on_failed: ExceptionList = Exception):
"""
A decorator to simplify writing doing-something loops. Basically, this:
>>> eb = ExponentialBackoff(start=2.5, limit=30)
>>> @eb.launch(TypeError)
>>> def do_action(*args, **kwargs):
>>> x_do_action(*args, **kwargs)
>>> do_action(5, test=True)
is equivalent to this:
>>> eb = ExponentialBackoff(start=2.5, limit=30)
>>> while True:
>>> try:
>>> x_do_action(5, test=True)
>>> except TypeError:
>>> eb.failed()
>>> eb.sleep()
:param exceptions_on_failed: a list of a single exception of exceptions
whose raising will signal that fun has failed
:return: a function, that called, will pass the exactly same parameters
"""
def outer(fun):
@wraps(fun)
def inner(*args, **kwargs):
try:
r = fun(*args, **kwargs)
self.success()
return r
except exceptions_on_failed:
self.failed()
self.sleep()
return inner
return outer
......@@ -38,6 +38,22 @@ class TestTime(unittest.TestCase):
time.sleep(1)
eb.success()
def test_exponential_backoff_launch(self):
eb = ExponentialBackoff(start=2, limit=30)
i = 1
@eb.launch(ValueError)
def do_action():
nonlocal i
if i == 3:
return
else:
i += 1
raise ValueError()
with measure() as m:
do_action()
self.assertGreaterEqual(m(), 2)
def test_exponential_backoff_waiting_for_service_healthy(self):
eb = ExponentialBackoff(start=2, limit=30)
self.assertTrue(eb.ready_for_next_check)
......
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