Send REQUEST message with exponential backoff retry.
(
self,
command: str,
params: dict[str, Any],
timeout_ms: int | None = None,
retry_initial_ms: int | None = None,
retry_max_ms: int | None = None,
retry_max_time_ms: int | None = None,
)
| 225 | _RETRYABLE_CODES = frozenset({"INSTANCE_RELOADING", "INSTANCE_BUSY", "TIMEOUT", "INSTANCE_DISCONNECTED"}) |
| 226 | |
| 227 | def send_request( |
| 228 | self, |
| 229 | command: str, |
| 230 | params: dict[str, Any], |
| 231 | timeout_ms: int | None = None, |
| 232 | retry_initial_ms: int | None = None, |
| 233 | retry_max_ms: int | None = None, |
| 234 | retry_max_time_ms: int | None = None, |
| 235 | ) -> dict[str, Any]: |
| 236 | """Send REQUEST message with exponential backoff retry.""" |
| 237 | timeout_ms = timeout_ms if timeout_ms is not None else self.timeout_ms |
| 238 | retry_initial_ms = retry_initial_ms if retry_initial_ms is not None else self.retry_initial_ms |
| 239 | retry_max_ms = retry_max_ms if retry_max_ms is not None else self.retry_max_ms |
| 240 | retry_max_time_ms = retry_max_time_ms if retry_max_time_ms is not None else self.retry_max_time_ms |
| 241 | |
| 242 | request_id = _generate_request_id(self._client_id) |
| 243 | start_time = time.time() |
| 244 | attempt = 0 |
| 245 | |
| 246 | while True: |
| 247 | elapsed_ms = (time.time() - start_time) * 1000 |
| 248 | |
| 249 | if attempt > 0 and elapsed_ms >= retry_max_time_ms: |
| 250 | raise TimeoutError( |
| 251 | f"Max retry time exceeded ({retry_max_time_ms}ms) for '{command}'", |
| 252 | "RETRY_TIMEOUT", |
| 253 | ) |
| 254 | |
| 255 | try: |
| 256 | return self._send_request_once(request_id, command, params, timeout_ms) |
| 257 | except (InstanceError, TimeoutError) as e: |
| 258 | self._maybe_retry(e, command, elapsed_ms, retry_initial_ms, retry_max_ms, retry_max_time_ms, attempt) |
| 259 | attempt += 1 |
| 260 | |
| 261 | def _maybe_retry( |
| 262 | self, |