request.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. from typing import Any, Callable, Type
  2. import requests
  3. from requests.exceptions import (
  4. ChunkedEncodingError,
  5. ConnectionError,
  6. )
  7. from tenacity import (
  8. retry,
  9. retry_if_exception,
  10. retry_if_exception_type,
  11. stop_after_delay,
  12. wait_exponential,
  13. )
  14. from urllib3.exceptions import IncompleteRead
  15. from openhands.utils.tenacity_stop import stop_if_should_exit
  16. def is_server_error(exception):
  17. return (
  18. isinstance(exception, requests.HTTPError)
  19. and exception.response.status_code >= 500
  20. )
  21. def is_404_error(exception):
  22. return (
  23. isinstance(exception, requests.HTTPError)
  24. and exception.response.status_code == 404
  25. )
  26. def is_503_error(exception):
  27. return (
  28. isinstance(exception, requests.HTTPError)
  29. and exception.response.status_code == 503
  30. )
  31. def is_502_error(exception):
  32. return (
  33. isinstance(exception, requests.HTTPError)
  34. and exception.response.status_code == 502
  35. )
  36. DEFAULT_RETRY_EXCEPTIONS = [
  37. ConnectionError,
  38. IncompleteRead,
  39. ChunkedEncodingError,
  40. ]
  41. def send_request_with_retry(
  42. session: requests.Session,
  43. method: str,
  44. url: str,
  45. timeout: int,
  46. retry_exceptions: list[Type[Exception]] | None = None,
  47. retry_fns: list[Callable[[Exception], bool]] | None = None,
  48. **kwargs: Any,
  49. ) -> requests.Response:
  50. exceptions_to_catch = retry_exceptions or DEFAULT_RETRY_EXCEPTIONS
  51. retry_condition = retry_if_exception_type(
  52. tuple(exceptions_to_catch)
  53. ) | retry_if_exception(is_502_error)
  54. if retry_fns is not None:
  55. for fn in retry_fns:
  56. retry_condition |= retry_if_exception(fn)
  57. # wait a few more seconds to get the timeout error from client side
  58. kwargs['timeout'] = timeout + 10
  59. @retry(
  60. stop=stop_after_delay(timeout) | stop_if_should_exit(),
  61. wait=wait_exponential(multiplier=1, min=4, max=20),
  62. retry=retry_condition,
  63. reraise=True,
  64. )
  65. def _send_request_with_retry():
  66. response = session.request(method, url, **kwargs)
  67. response.raise_for_status()
  68. return response
  69. return _send_request_with_retry()