fauna.client.retryable
1import abc 2from dataclasses import dataclass 3from random import random 4from time import sleep 5from typing import Callable, Optional, TypeVar, Generic 6 7from fauna.errors import RetryableFaunaException 8 9 10class RetryStrategy: 11 12 @abc.abstractmethod 13 def wait(self) -> float: 14 pass 15 16 17class ExponentialBackoffStrategy(RetryStrategy): 18 19 def __init__(self, max_backoff: int): 20 self._max_backoff = float(max_backoff) 21 self._i = 0.0 22 23 def wait(self) -> float: 24 """Returns the number of seconds to wait for the next call.""" 25 backoff = random() * (2.0**self._i) 26 self._i += 1.0 27 return min(backoff, self._max_backoff) 28 29 30T = TypeVar('T') 31 32 33@dataclass 34class RetryableResponse(Generic[T]): 35 attempts: int 36 response: T 37 38 39class Retryable(Generic[T]): 40 """ 41 Retryable is a wrapper class that acts on a Callable that returns a T type. 42 """ 43 _strategy: RetryStrategy 44 _error: Optional[Exception] 45 46 def __init__( 47 self, 48 max_attempts: int, 49 max_backoff: int, 50 func: Callable[..., T], 51 *args, 52 **kwargs, 53 ): 54 self._max_attempts = max_attempts 55 self._strategy = ExponentialBackoffStrategy(max_backoff) 56 self._func = func 57 self._args = args 58 self._kwargs = kwargs 59 self._error = None 60 61 def run(self) -> RetryableResponse[T]: 62 """Runs the wrapped function. Retries up to max_attempts if the function throws a RetryableFaunaException. It propagates 63 the thrown exception if max_attempts is reached or if a non-retryable is thrown. 64 65 Returns the number of attempts and the response 66 """ 67 attempt = 0 68 while True: 69 sleep_time = 0.0 if attempt == 0 else self._strategy.wait() 70 sleep(sleep_time) 71 72 try: 73 attempt += 1 74 qs = self._func(*self._args, **self._kwargs) 75 return RetryableResponse[T](attempt, qs) 76 except RetryableFaunaException as e: 77 if attempt >= self._max_attempts: 78 raise e
class
RetryStrategy:
18class ExponentialBackoffStrategy(RetryStrategy): 19 20 def __init__(self, max_backoff: int): 21 self._max_backoff = float(max_backoff) 22 self._i = 0.0 23 24 def wait(self) -> float: 25 """Returns the number of seconds to wait for the next call.""" 26 backoff = random() * (2.0**self._i) 27 self._i += 1.0 28 return min(backoff, self._max_backoff)
@dataclass
class
RetryableResponse
class
Retryable(typing.Generic[~T]):
40class Retryable(Generic[T]): 41 """ 42 Retryable is a wrapper class that acts on a Callable that returns a T type. 43 """ 44 _strategy: RetryStrategy 45 _error: Optional[Exception] 46 47 def __init__( 48 self, 49 max_attempts: int, 50 max_backoff: int, 51 func: Callable[..., T], 52 *args, 53 **kwargs, 54 ): 55 self._max_attempts = max_attempts 56 self._strategy = ExponentialBackoffStrategy(max_backoff) 57 self._func = func 58 self._args = args 59 self._kwargs = kwargs 60 self._error = None 61 62 def run(self) -> RetryableResponse[T]: 63 """Runs the wrapped function. Retries up to max_attempts if the function throws a RetryableFaunaException. It propagates 64 the thrown exception if max_attempts is reached or if a non-retryable is thrown. 65 66 Returns the number of attempts and the response 67 """ 68 attempt = 0 69 while True: 70 sleep_time = 0.0 if attempt == 0 else self._strategy.wait() 71 sleep(sleep_time) 72 73 try: 74 attempt += 1 75 qs = self._func(*self._args, **self._kwargs) 76 return RetryableResponse[T](attempt, qs) 77 except RetryableFaunaException as e: 78 if attempt >= self._max_attempts: 79 raise e
Retryable is a wrapper class that acts on a Callable that returns a T type.
Retryable( max_attempts: int, max_backoff: int, func: Callable[..., ~T], *args, **kwargs)
47 def __init__( 48 self, 49 max_attempts: int, 50 max_backoff: int, 51 func: Callable[..., T], 52 *args, 53 **kwargs, 54 ): 55 self._max_attempts = max_attempts 56 self._strategy = ExponentialBackoffStrategy(max_backoff) 57 self._func = func 58 self._args = args 59 self._kwargs = kwargs 60 self._error = None
62 def run(self) -> RetryableResponse[T]: 63 """Runs the wrapped function. Retries up to max_attempts if the function throws a RetryableFaunaException. It propagates 64 the thrown exception if max_attempts is reached or if a non-retryable is thrown. 65 66 Returns the number of attempts and the response 67 """ 68 attempt = 0 69 while True: 70 sleep_time = 0.0 if attempt == 0 else self._strategy.wait() 71 sleep(sleep_time) 72 73 try: 74 attempt += 1 75 qs = self._func(*self._args, **self._kwargs) 76 return RetryableResponse[T](attempt, qs) 77 except RetryableFaunaException as e: 78 if attempt >= self._max_attempts: 79 raise e
Runs the wrapped function. Retries up to max_attempts if the function throws a RetryableFaunaException. It propagates the thrown exception if max_attempts is reached or if a non-retryable is thrown.
Returns the number of attempts and the response