|
2 | 2 | JSON-RPC methods and helper functions for EEST consume based hive simulators. |
3 | 3 | """ |
4 | 4 |
|
| 5 | +import logging |
5 | 6 | import time |
6 | 7 | from itertools import count |
7 | 8 | from pprint import pprint |
|
10 | 11 | import requests |
11 | 12 | from jwt import encode |
12 | 13 | from pydantic import ValidationError |
| 14 | +from tenacity import ( |
| 15 | + before_sleep_log, |
| 16 | + retry, |
| 17 | + retry_if_exception_type, |
| 18 | + stop_after_attempt, |
| 19 | + wait_exponential, |
| 20 | +) |
13 | 21 |
|
14 | 22 | from ethereum_test_base_types import Address, Bytes, Hash, to_json |
15 | 23 | from ethereum_test_types import Transaction |
@@ -88,6 +96,34 @@ def __init_subclass__(cls, namespace: str | None = None) -> None: |
88 | 96 | namespace = namespace.lower() |
89 | 97 | cls.namespace = namespace |
90 | 98 |
|
| 99 | + @retry( |
| 100 | + retry=retry_if_exception_type((requests.ConnectionError, ConnectionRefusedError)), |
| 101 | + stop=stop_after_attempt(5), |
| 102 | + wait=wait_exponential(multiplier=0.5, min=0.5, max=4.0), |
| 103 | + before_sleep=before_sleep_log(logger, logging.WARNING), |
| 104 | + reraise=True, |
| 105 | + ) |
| 106 | + def _make_request( |
| 107 | + self, |
| 108 | + url: str, |
| 109 | + json_payload: dict, |
| 110 | + headers: dict, |
| 111 | + timeout: int | None, |
| 112 | + ) -> requests.Response: |
| 113 | + """ |
| 114 | + Make HTTP POST request with retry logic for connection errors only. |
| 115 | +
|
| 116 | + This method only retries network-level connection failures |
| 117 | + (ConnectionError, ConnectionRefusedError). HTTP status errors (4xx/5xx) |
| 118 | + are handled by the caller using response.raise_for_status() WITHOUT |
| 119 | + retries because: |
| 120 | + - 4xx errors are client errors (permanent failures, no point retrying) |
| 121 | + - 5xx errors are server errors that typically indicate |
| 122 | + application-level issues rather than transient network problems |
| 123 | + """ |
| 124 | + logger.debug(f"Making HTTP request to {url}, timeout={timeout}") |
| 125 | + return requests.post(url, json=json_payload, headers=headers, timeout=timeout) |
| 126 | + |
91 | 127 | def post_request( |
92 | 128 | self, |
93 | 129 | *, |
@@ -123,8 +159,12 @@ def post_request( |
123 | 159 | } |
124 | 160 | headers = base_header | extra_headers |
125 | 161 |
|
126 | | - logger.debug(f"Sending RPC request, timeout is set to {timeout}...") |
127 | | - response = requests.post(self.url, json=payload, headers=headers, timeout=timeout) |
| 162 | + logger.debug( |
| 163 | + f"Sending RPC request to {self.url}, method={self.namespace}_{method}, " |
| 164 | + f"timeout={timeout}..." |
| 165 | + ) |
| 166 | + |
| 167 | + response = self._make_request(self.url, payload, headers, timeout) |
128 | 168 | response.raise_for_status() |
129 | 169 | response_json = response.json() |
130 | 170 |
|
|
0 commit comments