diff --git a/zulip/zulip/__init__.py b/zulip/zulip/__init__.py index a363955ad..3791e50ab 100644 --- a/zulip/zulip/__init__.py +++ b/zulip/zulip/__init__.py @@ -601,8 +601,16 @@ def call_on_each_event( if narrow is None: narrow = [] - def do_register() -> Tuple[str, int]: - while True: + queue_id = None + # NOTE: Back off exponentially to cover against potential bugs in this + # library causing a DoS attack against a server when getting errors + # (explicit values listed for clarity) + backoff = RandomExponentialBackoff(maximum_retries=10, + timeout_success_equivalent=300, + delay_cap=90) + while backoff.keep_going(): + # Ensure event queue exists (or continues to do so) + if queue_id is None: if event_types is None: res = self.register() else: @@ -611,18 +619,15 @@ def do_register() -> Tuple[str, int]: if 'error' in res['result']: if self.verbose: print("Server returned error:\n%s" % res['msg']) - time.sleep(1) + backoff.fail() + continue else: - return (res['queue_id'], res['last_event_id']) - - queue_id = None - # Make long-polling requests with `get_events`. Once a request - # has received an answer, pass it to the callback and before - # making a new long-polling request. - while True: - if queue_id is None: - (queue_id, last_event_id) = do_register() + backoff.succeed() + queue_id, last_event_id = res['queue_id'], res['last_event_id'] + # Make long-polling requests with `get_events`. Once a request + # has received an answer, pass it to the callback and before + # making a new long-polling request. res = self.get_events(queue_id=queue_id, last_event_id=last_event_id) if 'error' in res['result']: if res["result"] == "http-error": @@ -649,12 +654,11 @@ def do_register() -> Tuple[str, int]: # # Reset queue_id to register a new event queue. queue_id = None - # Add a pause here to cover against potential bugs in this library - # causing a DoS attack against a server when getting errors. - # TODO: Make this back off exponentially. - time.sleep(1) + + backoff.fail() continue + backoff.succeed() for event in res['events']: last_event_id = max(last_event_id, int(event['id'])) callback(event)