How to implement retry mechanism into python requests library?

前端 未结 6 2004
春和景丽
春和景丽 2020-12-02 10:12

I would like to add a retry mechanism to python request library, so scripts that are using it will retry for non fatal errors.

At this moment I do consider three kin

相关标签:
6条回答
  • 2020-12-02 10:15

    Method to retry certain logic if some exception has occured at time intervals t1=1 sec, t2=2 sec, t3=4 sec. We can increase/decrease the time interval as well.

    MAX_RETRY = 3
    retries = 0
    
    try:
    
        call_to_api() // some business logic goes here.
    
    except Exception as exception:
    
        retries += 1
        if retries <= MAX_RETRY:
            print("ERROR=Method failed. Retrying ... #%s", retries)
            time.sleep((1 << retries) * 1) // retry happens after time as a exponent of 2
            continue
        else:
            raise Exception(exception)
    
    0 讨论(0)
  • 2020-12-02 10:33

    This is a snippet of code I used to retry for the petitions made with urllib2. Maybe you could use it for your purposes:

    retries = 1
    success = False
    while not success:
        try:
            response = urllib2.urlopen(request)
            success = True
        except Exception as e:
            wait = retries * 30;
            print 'Error! Waiting %s secs and re-trying...' % wait
            sys.stdout.flush()
            time.sleep(wait)
            retries += 1
    

    The waiting time grows incrementally to avoid be banned from server.

    0 讨论(0)
  • 2020-12-02 10:34

    This snippet of code will make all HTTP requests from the same session retry for a total of 5 times, sleeping between retries with an increasing backoff of 0s, 2s, 4s, 8s, 16s (the first retry is done immediately). It will retry on basic connectivity issues (including DNS lookup failures), and HTTP status codes of 502, 503 and 504.

    import logging
    import requests
    
    from requests.adapters import HTTPAdapter
    from requests.packages.urllib3.util.retry import Retry
    
    logging.basicConfig(level=logging.DEBUG)
    
    s = requests.Session()
    retries = Retry(total=5, backoff_factor=1, status_forcelist=[ 502, 503, 504 ])
    s.mount('http://', HTTPAdapter(max_retries=retries))
    
    s.get("http://httpstat.us/503")
    

    See Retry class for details.

    0 讨论(0)
  • 2020-12-02 10:35

    Possible solution using retrying package

    from retrying import retry
    import requests
    
    
    def retry_if_connection_error(exception):
        """ Specify an exception you need. or just True"""
        #return True
        return isinstance(exception, ConnectionError)
    
    # if exception retry with 2 second wait  
    @retry(retry_on_exception=retry_if_connection_error, wait_fixed=2000)
    def safe_request(url, **kwargs):
        return requests.get(url, **kwargs)
    
    response = safe_request('test.com')
    
    0 讨论(0)
  • 2020-12-02 10:37
    from requests.adapters import HTTPAdapter
    from urllib3.util.retry import Retry
    
    
    MAX_RETRY = 2
    MAX_RETRY_FOR_SESSION = 2
    BACK_OFF_FACTOR = 0.3
    TIME_BETWEEN_RETRIES = 1000
    ERROR_CODES = (500, 502, 504)
    
    
    def requests_retry_session(retries=MAX_RETRY_FOR_SESSION,
        back_off_factor=BACK_OFF_FACTOR,
        status_force_list=ERROR_CODES, 
        session=None):
           session = session  
           retry = Retry(total=retries, read=retries, connect=retries,
                         backoff_factor=back_off_factor,
                         status_forcelist=status_force_list,
                         method_whitelist=frozenset(['GET', 'POST']))
           adapter = HTTPAdapter(max_retries=retry)
           session.mount('http://', adapter)
           session.mount('https://', adapter)
           return session
    
    
    
    class ConfigService:
    
       def __init__(self):
          self.session = requests_retry_session(session=requests.Session())
    
       def call_to_api():
          config_url = 'http://localhost:8080/predict/'
          headers = {
            "Content-Type": "application/json",
            "x-api-key": self.x_api_key
          } 
          response = self.session.get(config_url, headers=headers)
          return response
    
    0 讨论(0)
  • 2020-12-02 10:37

    I was able to obtain the desired level of reliability by extending requests.Session class.

    Here is the code https://bitbucket.org/bspeakmon/jira-python/src/a7fca855394402f58507ca4056de87ccdbd6a213/jira/resilientsession.py?at=master

    EDIT That code was:

    from requests import Session
    from requests.exceptions import ConnectionError
    import logging
    import time
    
    
    class ResilientSession(Session):
    
        """
        This class is supposed to retry requests that do return temporary errors.
    
        At this moment it supports: 502, 503, 504
        """
    
        def __recoverable(self, error, url, request, counter=1):
            if hasattr(error,'status_code'):
                if error.status_code in [502, 503, 504]:
                    error = "HTTP %s" % error.status_code
                else:
                    return False
            DELAY = 10 * counter
            logging.warn("Got recoverable error [%s] from %s %s, retry #%s in %ss" % (error, request, url, counter, DELAY))
            time.sleep(DELAY)
            return True
    
    
        def get(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).get(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
                if self.__recoverable(r, url, 'GET', counter):
                    continue
                return r
    
        def post(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).post(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
                if self.__recoverable(r, url, 'POST', counter):
                    continue
                return r
    
        def delete(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).delete(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
                if self.__recoverable(r, url, 'DELETE', counter):
                    continue
                return r
    
        def put(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).put(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
    
                if self.__recoverable(r, url, 'PUT', counter):
                    continue
                return r
    
        def head(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).head(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
                if self.__recoverable(r, url, 'HEAD', counter):
                    continue
                return r
    
        def patch(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).patch(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
    
                if self.__recoverable(r, url, 'PATCH', counter):
                    continue
                return r
    
        def options(self, url, **kwargs):
            counter = 0
            while True:
                counter += 1
                try:
                    r = super(ResilientSession, self).options(url, **kwargs)
                except ConnectionError as e:
                    r = e.message
    
                if self.__recoverable(r, url, 'OPTIONS', counter):
                    continue
                return r
    
    0 讨论(0)
提交回复
热议问题