Skip to content

Commit b870097

Browse files
committed
zulip.Client.call_endpoint: Add retry_on_rate_limit_error.
If the call_endpoint method is called with the "retry_on_rate_limit_error" parameter set to true, wait and retry automatically on rate limit errors. See https://chat.zulip.org/#narrow/stream/378-api-design/topic/ Rate.20limits/near/1217048 for the discussion.
1 parent 71d488e commit b870097

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

zulip/zulip/__init__.py

+25-8
Original file line numberDiff line numberDiff line change
@@ -697,24 +697,41 @@ def call_endpoint(
697697
method: str = "POST",
698698
request: Optional[Dict[str, Any]] = None,
699699
longpolling: bool = False,
700+
retry_on_rate_limit_error: bool = False,
700701
files: Optional[List[IO[Any]]] = None,
701702
timeout: Optional[float] = None,
702703
) -> Dict[str, Any]:
704+
secs: float
705+
703706
if request is None:
704707
request = dict()
705708
marshalled_request = {}
706709
for (k, v) in request.items():
707710
if v is not None:
708711
marshalled_request[k] = v
709712
versioned_url = API_VERSTRING + (url if url is not None else "")
710-
return self.do_api_query(
711-
marshalled_request,
712-
versioned_url,
713-
method=method,
714-
longpolling=longpolling,
715-
files=files,
716-
timeout=timeout,
717-
)
713+
714+
while True:
715+
result = self.do_api_query(
716+
marshalled_request,
717+
versioned_url,
718+
method=method,
719+
longpolling=longpolling,
720+
files=files,
721+
timeout=timeout,
722+
)
723+
if not retry_on_rate_limit_error or result["result"] == "success":
724+
break
725+
elif "code" in result and result["code"] == "RATE_LIMIT_HIT":
726+
secs = result["retry-after"]
727+
elif "X-RateLimit-Reset" in result:
728+
secs = float(result["X-RateLimit-Reset"])
729+
else:
730+
break
731+
logger.warning("hit API rate limit, waiting for %f seconds...", secs)
732+
time.sleep(secs)
733+
734+
return result
718735

719736
def call_on_each_event(
720737
self,

0 commit comments

Comments
 (0)