图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.1 KiB

  1. import random
  2. from abc import ABC, abstractmethod
  3. # Maximum backoff between each retry in seconds
  4. DEFAULT_CAP = 0.512
  5. # Minimum backoff between each retry in seconds
  6. DEFAULT_BASE = 0.008
  7. class AbstractBackoff(ABC):
  8. """Backoff interface"""
  9. def reset(self):
  10. """
  11. Reset internal state before an operation.
  12. `reset` is called once at the beginning of
  13. every call to `Retry.call_with_retry`
  14. """
  15. pass
  16. @abstractmethod
  17. def compute(self, failures: int) -> float:
  18. """Compute backoff in seconds upon failure"""
  19. pass
  20. class ConstantBackoff(AbstractBackoff):
  21. """Constant backoff upon failure"""
  22. def __init__(self, backoff: float) -> None:
  23. """`backoff`: backoff time in seconds"""
  24. self._backoff = backoff
  25. def compute(self, failures: int) -> float:
  26. return self._backoff
  27. class NoBackoff(ConstantBackoff):
  28. """No backoff upon failure"""
  29. def __init__(self) -> None:
  30. super().__init__(0)
  31. class ExponentialBackoff(AbstractBackoff):
  32. """Exponential backoff upon failure"""
  33. def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE):
  34. """
  35. `cap`: maximum backoff time in seconds
  36. `base`: base backoff time in seconds
  37. """
  38. self._cap = cap
  39. self._base = base
  40. def compute(self, failures: int) -> float:
  41. return min(self._cap, self._base * 2**failures)
  42. class FullJitterBackoff(AbstractBackoff):
  43. """Full jitter backoff upon failure"""
  44. def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
  45. """
  46. `cap`: maximum backoff time in seconds
  47. `base`: base backoff time in seconds
  48. """
  49. self._cap = cap
  50. self._base = base
  51. def compute(self, failures: int) -> float:
  52. return random.uniform(0, min(self._cap, self._base * 2**failures))
  53. class EqualJitterBackoff(AbstractBackoff):
  54. """Equal jitter backoff upon failure"""
  55. def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
  56. """
  57. `cap`: maximum backoff time in seconds
  58. `base`: base backoff time in seconds
  59. """
  60. self._cap = cap
  61. self._base = base
  62. def compute(self, failures: int) -> float:
  63. temp = min(self._cap, self._base * 2**failures) / 2
  64. return temp + random.uniform(0, temp)
  65. class DecorrelatedJitterBackoff(AbstractBackoff):
  66. """Decorrelated jitter backoff upon failure"""
  67. def __init__(self, cap: float = DEFAULT_CAP, base: float = DEFAULT_BASE) -> None:
  68. """
  69. `cap`: maximum backoff time in seconds
  70. `base`: base backoff time in seconds
  71. """
  72. self._cap = cap
  73. self._base = base
  74. self._previous_backoff = 0
  75. def reset(self) -> None:
  76. self._previous_backoff = 0
  77. def compute(self, failures: int) -> float:
  78. max_backoff = max(self._base, self._previous_backoff * 3)
  79. temp = random.uniform(self._base, max_backoff)
  80. self._previous_backoff = min(self._cap, temp)
  81. return self._previous_backoff
  82. def default_backoff():
  83. return EqualJitterBackoff()