Mirrowel commited on
Commit
bf79e30
·
1 Parent(s): 2683513

feat: Enhance error handling in UsageManager to extract retry delay from multiple error message formats

Browse files
src/rotator_library/client.py CHANGED
@@ -19,7 +19,7 @@ if not lib_logger.handlers:
19
 
20
  from .usage_manager import UsageManager
21
  from .failure_logger import log_failure
22
- from .error_handler import is_server_error, is_unrecoverable_error
23
  from .providers import PROVIDER_PLUGINS
24
 
25
  class RotatingClient:
@@ -136,8 +136,8 @@ class RotatingClient:
136
  )
137
 
138
  # For any retriable server error, we just continue the attempt loop
139
- if is_server_error(e) and attempt < self.max_retries - 1:
140
- print(f"Key ...{current_key[-4:]} failed with server error. Retrying...")
141
  await asyncio.sleep(1 * (attempt + 1))
142
  continue
143
 
 
19
 
20
  from .usage_manager import UsageManager
21
  from .failure_logger import log_failure
22
+ from .error_handler import is_rate_limit_error, is_server_error, is_unrecoverable_error
23
  from .providers import PROVIDER_PLUGINS
24
 
25
  class RotatingClient:
 
136
  )
137
 
138
  # For any retriable server error, we just continue the attempt loop
139
+ if is_server_error(e) or is_rate_limit_error(e) and attempt < self.max_retries - 1:
140
+ print(f"Key ...{current_key[-4:]} failed with server error or rate limit error. Retrying...")
141
  await asyncio.sleep(1 * (attempt + 1))
142
  continue
143
 
src/rotator_library/usage_manager.py CHANGED
@@ -6,6 +6,7 @@ from datetime import date, datetime
6
  from typing import Dict, List, Optional, Any
7
  from filelock import FileLock
8
  import litellm
 
9
 
10
  lib_logger = logging.getLogger('rotator_library')
11
  lib_logger.propagate = False # Ensure this logger doesn't propagate to root
@@ -128,7 +129,44 @@ class UsageManager:
128
  error_str = str(error).lower()
129
  if "retry_delay" in error_str:
130
  try:
131
- delay_str = error_str.split("retry_delay")[1].split("seconds:")[1].strip().split("}")[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  cooldown_seconds = int(delay_str)
133
  except (IndexError, ValueError):
134
  pass
 
6
  from typing import Dict, List, Optional, Any
7
  from filelock import FileLock
8
  import litellm
9
+ import re
10
 
11
  lib_logger = logging.getLogger('rotator_library')
12
  lib_logger.propagate = False # Ensure this logger doesn't propagate to root
 
129
  error_str = str(error).lower()
130
  if "retry_delay" in error_str:
131
  try:
132
+ # Try multiple patterns to extract delay from error message
133
+ delay_str = None
134
+
135
+ # Pattern 1: retry_delay...seconds format
136
+ if "retry_delay" in error_str and "seconds:" in error_str:
137
+ try:
138
+ delay_str = error_str.split("retry_delay")[1].split("seconds:")[1].strip().split("}")[0]
139
+ except (IndexError, AttributeError):
140
+ pass
141
+
142
+ # Pattern 2: retryDelay with 's' suffix (Gemini format)
143
+ if not delay_str and "retrydelay" in error_str:
144
+ try:
145
+ match = re.search(r'"retrydelay":\s*"(\d+)s"', error_str)
146
+ if match:
147
+ delay_str = match.group(1)
148
+ except Exception:
149
+ pass
150
+
151
+ # Pattern 3: Generic numeric extraction for retry/delay contexts
152
+ if not delay_str:
153
+ try:
154
+ # Look for numbers followed by 's' or 'seconds' in retry/delay context
155
+ patterns = [
156
+ r'retry.*?(\d+)s',
157
+ r'delay.*?(\d+)s',
158
+ r'wait.*?(\d+)\s*seconds?'
159
+ ]
160
+ for pattern in patterns:
161
+ match = re.search(pattern, error_str, re.IGNORECASE)
162
+ if match:
163
+ delay_str = match.group(1)
164
+ break
165
+ except Exception:
166
+ pass
167
+
168
+ if delay_str:
169
+ cooldown_seconds = int(delay_str)
170
  cooldown_seconds = int(delay_str)
171
  except (IndexError, ValueError):
172
  pass