Spaces:
Paused
Paused
Mirrowel commited on
Commit ·
5a4ba9e
1
Parent(s): f8d59cd
feat(rotator): stream real-time key rotation errors to client
Browse filesThis change ensures that clients consuming the API are immediately notified when an API key fails and is being rotated. Previously, clients would experience a silent delay or connection termination.
- Sends `proxy_key_rotation_error` messages through the stream when a key encounters issues like rate limits or general failures.
- Provides immediate feedback, improving the overall user experience and allowing clients to react appropriately without losing connection.
src/rotator_library/client.py
CHANGED
|
@@ -367,6 +367,19 @@ class RotatingClient:
|
|
| 367 |
last_exception = e
|
| 368 |
log_failure(api_key=current_key, model=model, attempt=attempt + 1, error=e, request_data=kwargs)
|
| 369 |
classified_error = classify_error(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 370 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed with {classified_error.error_type} (Status: {classified_error.status_code}). Error: {str(e)}. Rotating key.")
|
| 371 |
|
| 372 |
if classified_error.error_type == 'rate_limit' and classified_error.status_code == 429:
|
|
@@ -385,6 +398,16 @@ class RotatingClient:
|
|
| 385 |
|
| 386 |
if attempt >= self.max_retries - 1:
|
| 387 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed after {self.max_retries} retries with {classified_error.error_type}. Rotating key.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
break
|
| 389 |
|
| 390 |
wait_time = classified_error.retry_after or (1 * (2 ** attempt)) + random.uniform(0, 1)
|
|
@@ -396,6 +419,19 @@ class RotatingClient:
|
|
| 396 |
last_exception = e
|
| 397 |
log_failure(api_key=current_key, model=model, attempt=attempt + 1, error=e, request_data=kwargs)
|
| 398 |
classified_error = classify_error(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed with {classified_error.error_type} (Status: {classified_error.status_code}). Error: {str(e)}. Rotating key.")
|
| 400 |
|
| 401 |
if classified_error.status_code == 429:
|
|
|
|
| 367 |
last_exception = e
|
| 368 |
log_failure(api_key=current_key, model=model, attempt=attempt + 1, error=e, request_data=kwargs)
|
| 369 |
classified_error = classify_error(e)
|
| 370 |
+
|
| 371 |
+
# Inform the client about the temporary failure before rotating.
|
| 372 |
+
# This keeps the connection alive.
|
| 373 |
+
error_message = f"Provider API key failed with {classified_error.error_type}. Rotating to a new key."
|
| 374 |
+
error_data = {
|
| 375 |
+
"error": {
|
| 376 |
+
"message": error_message,
|
| 377 |
+
"type": "proxy_key_rotation_error",
|
| 378 |
+
"code": classified_error.status_code
|
| 379 |
+
}
|
| 380 |
+
}
|
| 381 |
+
yield f"data: {json.dumps(error_data)}\n\n"
|
| 382 |
+
|
| 383 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed with {classified_error.error_type} (Status: {classified_error.status_code}). Error: {str(e)}. Rotating key.")
|
| 384 |
|
| 385 |
if classified_error.error_type == 'rate_limit' and classified_error.status_code == 429:
|
|
|
|
| 398 |
|
| 399 |
if attempt >= self.max_retries - 1:
|
| 400 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed after {self.max_retries} retries with {classified_error.error_type}. Rotating key.")
|
| 401 |
+
# Inform the client about the temporary failure before rotating.
|
| 402 |
+
error_message = f"Key ...{current_key[-4:]} failed after multiple retries. Rotating to a new key."
|
| 403 |
+
error_data = {
|
| 404 |
+
"error": {
|
| 405 |
+
"message": error_message,
|
| 406 |
+
"type": "proxy_key_rotation_error",
|
| 407 |
+
"code": classified_error.status_code
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
yield f"data: {json.dumps(error_data)}\n\n"
|
| 411 |
break
|
| 412 |
|
| 413 |
wait_time = classified_error.retry_after or (1 * (2 ** attempt)) + random.uniform(0, 1)
|
|
|
|
| 419 |
last_exception = e
|
| 420 |
log_failure(api_key=current_key, model=model, attempt=attempt + 1, error=e, request_data=kwargs)
|
| 421 |
classified_error = classify_error(e)
|
| 422 |
+
|
| 423 |
+
# For most exceptions, we notify the client and rotate the key.
|
| 424 |
+
if classified_error.error_type not in ['invalid_request', 'context_window_exceeded', 'authentication']:
|
| 425 |
+
error_message = f"An unexpected error occurred with key ...{current_key[-4:]}. Rotating to a new key."
|
| 426 |
+
error_data = {
|
| 427 |
+
"error": {
|
| 428 |
+
"message": error_message,
|
| 429 |
+
"type": "proxy_key_rotation_error",
|
| 430 |
+
"code": classified_error.status_code
|
| 431 |
+
}
|
| 432 |
+
}
|
| 433 |
+
yield f"data: {json.dumps(error_data)}\n\n"
|
| 434 |
+
|
| 435 |
lib_logger.warning(f"Key ...{current_key[-4:]} failed with {classified_error.error_type} (Status: {classified_error.status_code}). Error: {str(e)}. Rotating key.")
|
| 436 |
|
| 437 |
if classified_error.status_code == 429:
|