Mirrowel commited on
Commit
5a4ba9e
·
1 Parent(s): f8d59cd

feat(rotator): stream real-time key rotation errors to client

Browse files

This 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.

Files changed (1) hide show
  1. src/rotator_library/client.py +36 -0
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: