retry_util.py 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. import logging
  2. import time
  3. from typing import Callable, TypeVar
  4. logger = logging.getLogger(__name__)
  5. T = TypeVar("T")
  6. def retry_on_failure(
  7. fn: Callable[[], T],
  8. *,
  9. max_retries: int = 3,
  10. backoff_base: float = 2.0,
  11. task_name: str = "",
  12. ) -> T:
  13. """在失败时使用指数退避进行重试,仅用于任务提交阶段。
  14. fn 应当在提交不成功时抛出异常,所有重试耗尽后将抛出最后一次的异常。
  15. """
  16. last_exc: Exception | None = None
  17. for attempt in range(1, max_retries + 1):
  18. try:
  19. return fn()
  20. except Exception as e:
  21. last_exc = e
  22. if attempt < max_retries:
  23. wait = backoff_base ** attempt
  24. logger.warning(
  25. "[%s] Submit attempt %d/%d failed: %s, retrying in %.1fs …",
  26. task_name, attempt, max_retries, e, wait,
  27. )
  28. time.sleep(wait)
  29. else:
  30. logger.error(
  31. "[%s] All %d submit attempts exhausted, last error: %s",
  32. task_name, max_retries, e,
  33. )
  34. raise last_exc # type: ignore[misc]