|
17 | 17 | import random |
18 | 18 | import socket |
19 | 19 | from typing import Dict, Any, List, Optional, Union, Tuple |
| 20 | +from botocore.config import Config |
20 | 21 | from botocore.exceptions import ClientError, ReadTimeoutError, ConnectTimeoutError, EndpointConnectionError |
21 | 22 | from urllib3.exceptions import ReadTimeoutError as Urllib3ReadTimeoutError |
22 | 23 | try: |
@@ -73,8 +74,12 @@ def __init__( |
73 | 74 | @property |
74 | 75 | def client(self): |
75 | 76 | """Lazy-loaded Bedrock client.""" |
| 77 | + config = Config( |
| 78 | + connect_timeout=10, |
| 79 | + read_timeout=120 |
| 80 | + ) |
76 | 81 | if self._client is None: |
77 | | - self._client = boto3.client('bedrock-runtime', region_name=self.region) |
| 82 | + self._client = boto3.client('bedrock-runtime', region_name=self.region, config=config) |
78 | 83 | return self._client |
79 | 84 |
|
80 | 85 | def __call__( |
@@ -445,10 +450,47 @@ def _invoke_with_retry( |
445 | 450 |
|
446 | 451 | return response_with_metering |
447 | 452 |
|
448 | | - except ClientError as e: |
| 453 | + # except ClientError as e: |
| 454 | + except ReadTimeoutError as e |
| 455 | + error_code = "ReadTimeoutError" |
| 456 | + error_message = str(e) |
| 457 | + |
| 458 | + self._put_metric('BedrockThrottles', 1) |
| 459 | + |
| 460 | + # Check if we've reached max retries |
| 461 | + if retry_count >= max_retries: |
| 462 | + logger.error(f"Max retries ({max_retries}) exceeded. Last error: {error_message}") |
| 463 | + self._put_metric('BedrockRequestsFailed', 1) |
| 464 | + self._put_metric('BedrockMaxRetriesExceeded', 1) |
| 465 | + raise |
| 466 | + |
| 467 | + # Calculate backoff time |
| 468 | + backoff = self._calculate_backoff(retry_count) |
| 469 | + logger.warning(f"Bedrock throttling occurred (attempt {retry_count + 1}/{max_retries}). " |
| 470 | + f"Error: {error_message}. " |
| 471 | + f"Backing off for {backoff:.2f}s") |
| 472 | + |
| 473 | + # Sleep for backoff period |
| 474 | + time.sleep(backoff) |
| 475 | + |
| 476 | + # Recursive call with incremented retry count |
| 477 | + return self._invoke_with_retry( |
| 478 | + converse_params=converse_params, |
| 479 | + retry_count=retry_count + 1, |
| 480 | + max_retries=max_retries, |
| 481 | + request_start_time=request_start_time, |
| 482 | + last_exception=e, |
| 483 | + context=context |
| 484 | + ) |
| 485 | + except Exception as e: |
| 486 | + # logger.error(f"Unexpected error invoking Bedrock: {str(e)}", exc_info=True) |
| 487 | + self._put_metric('BedrockRequestsFailed', 1) |
| 488 | + self._put_metric('BedrockUnexpectedErrors', 1) |
| 489 | + |
| 490 | + # error_code = type(e) |
449 | 491 | error_code = e.response['Error']['Code'] |
450 | 492 | error_message = e.response['Error']['Message'] |
451 | | - |
| 493 | + |
452 | 494 | retryable_errors = [ |
453 | 495 | 'ThrottlingException', |
454 | 496 | 'ServiceQuotaExceededException', |
@@ -495,12 +537,6 @@ def _invoke_with_retry( |
495 | 537 | self._put_metric('BedrockRequestsFailed', 1) |
496 | 538 | self._put_metric('BedrockNonRetryableErrors', 1) |
497 | 539 | raise |
498 | | - |
499 | | - except Exception as e: |
500 | | - logger.error(f"Unexpected error invoking Bedrock: {str(e)}", exc_info=True) |
501 | | - self._put_metric('BedrockRequestsFailed', 1) |
502 | | - self._put_metric('BedrockUnexpectedErrors', 1) |
503 | | - raise |
504 | 540 |
|
505 | 541 | def get_guardrail_config(self) -> Optional[Dict[str, str]]: |
506 | 542 | """ |
|
0 commit comments