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:
11class RetryStrategy:
12
13  @abc.abstractmethod
14  def wait(self) -> float:
15    pass
@abc.abstractmethod
def wait(self) -> float:
13  @abc.abstractmethod
14  def wait(self) -> float:
15    pass
class ExponentialBackoffStrategy(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)
ExponentialBackoffStrategy(max_backoff: int)
20  def __init__(self, max_backoff: int):
21    self._max_backoff = float(max_backoff)
22    self._i = 0.0
def wait(self) -> float:
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)

Returns the number of seconds to wait for the next call.

@dataclass
class RetryableResponse(typing.Generic[~T]):
34@dataclass
35class RetryableResponse(Generic[T]):
36  attempts: int
37  response: T
RetryableResponse(attempts: int, response: ~T)
attempts: int
response: ~T
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
def run(self) -> RetryableResponse[~T]:
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