Move backoff classes to the Zulip API
(imported from commit 76c5d499874f0397c505ab3fcda631a1a46847b6)
This commit is contained in:
		
							parent
							
								
									ee04f7b3e8
								
							
						
					
					
						commit
						41a782e011
					
				
					 3 changed files with 37 additions and 35 deletions
				
			
		| 
						 | 
					@ -28,7 +28,6 @@ import traceback
 | 
				
			||||||
import signal
 | 
					import signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from zephyr_mirror_backend import parse_args
 | 
					from zephyr_mirror_backend import parse_args
 | 
				
			||||||
from zephyr_mirror_backend import RandomExponentialBackoff
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def die(signal, frame):
 | 
					def die(signal, frame):
 | 
				
			||||||
    # We actually want to exit, so run os._exit (so as not to be caught and restarted)
 | 
					    # We actually want to exit, so run os._exit (so as not to be caught and restarted)
 | 
				
			||||||
| 
						 | 
					@ -38,6 +37,9 @@ signal.signal(signal.SIGINT, die)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(options, args) = parse_args()
 | 
					(options, args) = parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sys.path[:0] = [os.path.join(options.root_path, 'api')]
 | 
				
			||||||
 | 
					from zulip import RandomExponentialBackoff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
args = [os.path.join(options.root_path, "user_root", "zephyr_mirror_backend.py")]
 | 
					args = [os.path.join(options.root_path, "user_root", "zephyr_mirror_backend.py")]
 | 
				
			||||||
args.extend(sys.argv[1:])
 | 
					args.extend(sys.argv[1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,39 +37,8 @@ import signal
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
import random
 | 
					 | 
				
			||||||
import select
 | 
					import select
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CountingBackoff(object):
 | 
					 | 
				
			||||||
    def __init__(self, maximum_retries=10):
 | 
					 | 
				
			||||||
        self.number_of_retries = 0
 | 
					 | 
				
			||||||
        self.maximum_retries = maximum_retries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def keep_going(self):
 | 
					 | 
				
			||||||
        return self.number_of_retries < self.maximum_retries
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def succeed(self):
 | 
					 | 
				
			||||||
        self.number_of_retries = 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def fail(self):
 | 
					 | 
				
			||||||
        self.number_of_retries = min(self.number_of_retries + 1,
 | 
					 | 
				
			||||||
                                     self.maximum_retries)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RandomExponentialBackoff(CountingBackoff):
 | 
					 | 
				
			||||||
    def fail(self):
 | 
					 | 
				
			||||||
        self.number_of_retries = min(self.number_of_retries + 1,
 | 
					 | 
				
			||||||
                                     self.maximum_retries)
 | 
					 | 
				
			||||||
        # Exponential growth with ratio sqrt(2); compute random delay
 | 
					 | 
				
			||||||
        # between x and 2x where x is growing exponentially
 | 
					 | 
				
			||||||
        delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
 | 
					 | 
				
			||||||
        delay = delay_scale + random.randint(1, delay_scale)
 | 
					 | 
				
			||||||
        message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            logger.warning(message)
 | 
					 | 
				
			||||||
        except NameError:
 | 
					 | 
				
			||||||
            print message
 | 
					 | 
				
			||||||
        time.sleep(delay)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEFAULT_SITE = "https://api.zulip.com"
 | 
					DEFAULT_SITE = "https://api.zulip.com"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class States:
 | 
					class States:
 | 
				
			||||||
| 
						 | 
					@ -478,7 +447,7 @@ def quit_failed_initialization(message):
 | 
				
			||||||
    sys.exit(1)
 | 
					    sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def zephyr_init_autoretry():
 | 
					def zephyr_init_autoretry():
 | 
				
			||||||
    backoff = RandomExponentialBackoff()
 | 
					    backoff = zulip.RandomExponentialBackoff()
 | 
				
			||||||
    while backoff.keep_going():
 | 
					    while backoff.keep_going():
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            # zephyr.init() tries to clear old subscriptions, and thus
 | 
					            # zephyr.init() tries to clear old subscriptions, and thus
 | 
				
			||||||
| 
						 | 
					@ -493,7 +462,7 @@ def zephyr_init_autoretry():
 | 
				
			||||||
    quit_failed_initialization("Could not initialize Zephyr library, quitting!")
 | 
					    quit_failed_initialization("Could not initialize Zephyr library, quitting!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def zephyr_load_session_autoretry(session_path):
 | 
					def zephyr_load_session_autoretry(session_path):
 | 
				
			||||||
    backoff = RandomExponentialBackoff()
 | 
					    backoff = zulip.RandomExponentialBackoff()
 | 
				
			||||||
    while backoff.keep_going():
 | 
					    while backoff.keep_going():
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            session = file(session_path, "r").read()
 | 
					            session = file(session_path, "r").read()
 | 
				
			||||||
| 
						 | 
					@ -508,7 +477,7 @@ def zephyr_load_session_autoretry(session_path):
 | 
				
			||||||
    quit_failed_initialization("Could not load saved Zephyr session, quitting!")
 | 
					    quit_failed_initialization("Could not load saved Zephyr session, quitting!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def zephyr_subscribe_autoretry(sub):
 | 
					def zephyr_subscribe_autoretry(sub):
 | 
				
			||||||
    backoff = RandomExponentialBackoff()
 | 
					    backoff = zulip.RandomExponentialBackoff()
 | 
				
			||||||
    while backoff.keep_going():
 | 
					    while backoff.keep_going():
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            zephyr.Subscriptions().add(sub)
 | 
					            zephyr.Subscriptions().add(sub)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ import os
 | 
				
			||||||
import optparse
 | 
					import optparse
 | 
				
			||||||
import platform
 | 
					import platform
 | 
				
			||||||
import urllib
 | 
					import urllib
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
from distutils.version import LooseVersion
 | 
					from distutils.version import LooseVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ConfigParser import SafeConfigParser
 | 
					from ConfigParser import SafeConfigParser
 | 
				
			||||||
| 
						 | 
					@ -46,6 +47,36 @@ requests_json_is_function = callable(requests.Response.json)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
API_VERSTRING = "v1/"
 | 
					API_VERSTRING = "v1/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CountingBackoff(object):
 | 
				
			||||||
 | 
					    def __init__(self, maximum_retries=10):
 | 
				
			||||||
 | 
					        self.number_of_retries = 0
 | 
				
			||||||
 | 
					        self.maximum_retries = maximum_retries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def keep_going(self):
 | 
				
			||||||
 | 
					        return self.number_of_retries < self.maximum_retries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def succeed(self):
 | 
				
			||||||
 | 
					        self.number_of_retries = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fail(self):
 | 
				
			||||||
 | 
					        self.number_of_retries = min(self.number_of_retries + 1,
 | 
				
			||||||
 | 
					                                     self.maximum_retries)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RandomExponentialBackoff(CountingBackoff):
 | 
				
			||||||
 | 
					    def fail(self):
 | 
				
			||||||
 | 
					        self.number_of_retries = min(self.number_of_retries + 1,
 | 
				
			||||||
 | 
					                                     self.maximum_retries)
 | 
				
			||||||
 | 
					        # Exponential growth with ratio sqrt(2); compute random delay
 | 
				
			||||||
 | 
					        # between x and 2x where x is growing exponentially
 | 
				
			||||||
 | 
					        delay_scale = int(2 ** (self.number_of_retries / 2.0 - 1)) + 1
 | 
				
			||||||
 | 
					        delay = delay_scale + random.randint(1, delay_scale)
 | 
				
			||||||
 | 
					        message = "Sleeping for %ss [max %s] before retrying." % (delay, delay_scale * 2)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            logger.warning(message)
 | 
				
			||||||
 | 
					        except NameError:
 | 
				
			||||||
 | 
					            print message
 | 
				
			||||||
 | 
					        time.sleep(delay)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _default_client():
 | 
					def _default_client():
 | 
				
			||||||
    return "ZulipPython/" + __version__
 | 
					    return "ZulipPython/" + __version__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue