1
1
from __future__ import annotations
2
2
import asyncio
3
+ from http import HTTPStatus
3
4
import logging
4
5
import time
5
6
from typing import Type
@@ -50,6 +51,20 @@ def before(retry_state: "RetryCallState"):
50
51
retry_state .start_time = time .monotonic ()
51
52
52
53
54
+ def is_retryable_http_error (e ) -> bool :
55
+ """Check for retryable HTTP status codes"""
56
+ return isinstance (e , HTTPError ) and e .response .status_code in [
57
+ HTTPStatus .TOO_MANY_REQUESTS ,
58
+ HTTPStatus .BAD_GATEWAY ,
59
+ HTTPStatus .GATEWAY_TIMEOUT ,
60
+ ]
61
+
62
+
63
+ def is_timeout_value_error (e ) -> bool :
64
+ """Check if a ValueError is due to an rpc request timeout."""
65
+ return isinstance (e , ValueError ) and "request failed or timed out" in str (e )
66
+
67
+
53
68
def get_retryable_eth_module (base : Type [Eth ] | Type [AsyncEth ], logger : logging .Logger , retry_stop : typing .Callable or None = None ):
54
69
class RetryableModule (base ):
55
70
def __getattribute__ (self , name ):
@@ -63,7 +78,8 @@ def __getattribute__(self, name):
63
78
retry_if_exception_type (
64
79
(BlockNotFound , TransactionNotFound , ConnectionError , ClientConnectorError , asyncio .TimeoutError )
65
80
),
66
- retry_if_exception (lambda e : isinstance (e , HTTPError ) and e .response .status_code in [429 , 502 , 504 ]),
81
+ retry_if_exception (is_retryable_http_error ),
82
+ retry_if_exception (is_timeout_value_error ),
67
83
),
68
84
wait = wait_fixed (5 ),
69
85
reraise = True ,
0 commit comments