@@ -393,6 +393,7 @@ def __init__(
393393 config_file : Optional [str ] = None ,
394394 verbose : bool = False ,
395395 retry_on_errors : bool = True ,
396+ auto_retry_rate_limits : bool = False ,
396397 site : Optional [str ] = None ,
397398 client : Optional [str ] = None ,
398399 cert_bundle : Optional [str ] = None ,
@@ -476,6 +477,7 @@ def __init__(
476477 self .api_key = api_key
477478 self .email = email
478479 self .verbose = verbose
480+ self .auto_retry_rate_limits = auto_retry_rate_limits
479481 if site is not None :
480482 if site .startswith ("localhost" ):
481483 site = "http://" + site
@@ -655,6 +657,23 @@ def end_error_retry(succeeded: bool) -> None:
655657
656658 self .has_connected = True
657659
660+ # On Rate Limit (429) Errors, pause the current thread with time.sleep()
661+ # And only retry if the user opted in sucessfully
662+ if res .status_code == 429 and self .auto_retry_rate_limits :
663+ try :
664+ # Zulip will return the wait time in the either the (JSON) body or header
665+ wait_time = float (
666+ res .json ().get ("retry-after" , res .headers .get ("Retry-After" , 1.0 ))
667+ )
668+ except Exception :
669+ wait_time = 1.0
670+ if self .verbose :
671+ print (
672+ f"Rate limit hit! Sleeping for { wait_time } seconds before retrying..."
673+ )
674+ time .sleep (wait_time )
675+ continue
676+
658677 # On 50x errors, try again after a short sleep
659678 if str (res .status_code ).startswith ("5" ) and error_retry (
660679 f" (server { res .status_code } )"
0 commit comments