图片解析应用
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.

67 lines
2.2 KiB

  1. from asyncio import sleep
  2. from typing import TYPE_CHECKING, Any, Awaitable, Callable, Tuple, Type, TypeVar
  3. from redis.exceptions import ConnectionError, RedisError, TimeoutError
  4. if TYPE_CHECKING:
  5. from redis.backoff import AbstractBackoff
  6. T = TypeVar("T")
  7. class Retry:
  8. """Retry a specific number of times after a failure"""
  9. __slots__ = "_backoff", "_retries", "_supported_errors"
  10. def __init__(
  11. self,
  12. backoff: "AbstractBackoff",
  13. retries: int,
  14. supported_errors: Tuple[Type[RedisError], ...] = (
  15. ConnectionError,
  16. TimeoutError,
  17. ),
  18. ):
  19. """
  20. Initialize a `Retry` object with a `Backoff` object
  21. that retries a maximum of `retries` times.
  22. `retries` can be negative to retry forever.
  23. You can specify the types of supported errors which trigger
  24. a retry with the `supported_errors` parameter.
  25. """
  26. self._backoff = backoff
  27. self._retries = retries
  28. self._supported_errors = supported_errors
  29. def update_supported_errors(self, specified_errors: list):
  30. """
  31. Updates the supported errors with the specified error types
  32. """
  33. self._supported_errors = tuple(
  34. set(self._supported_errors + tuple(specified_errors))
  35. )
  36. async def call_with_retry(
  37. self, do: Callable[[], Awaitable[T]], fail: Callable[[RedisError], Any]
  38. ) -> T:
  39. """
  40. Execute an operation that might fail and returns its result, or
  41. raise the exception that was thrown depending on the `Backoff` object.
  42. `do`: the operation to call. Expects no argument.
  43. `fail`: the failure handler, expects the last error that was thrown
  44. """
  45. self._backoff.reset()
  46. failures = 0
  47. while True:
  48. try:
  49. return await do()
  50. except self._supported_errors as error:
  51. failures += 1
  52. await fail(error)
  53. if self._retries >= 0 and failures > self._retries:
  54. raise error
  55. backoff = self._backoff.compute(failures)
  56. if backoff > 0:
  57. await sleep(backoff)