How a Python Professinal would retry running a function that will request a web service(the webservice sometimes fails)
The function:
def some_request(uri):
try:
req = requests.post('http://someuri.com', {'test': 'yes'})
except Exception as e:
return False
return {'id': req.json()['value'], 'other': req.json()['other']}
You handle the retry with a while or other python idiom?
Give me a clue on how to do it the right way.
Define retry utility:
# Retry utility
# set logging for `retry` channel
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('retry')
# Define Exception class for retry
class RetryException(Exception):
u_str = "Exception ({}) raised after {} tries."
def __init__(self, exp, max_retry):
self.exp = exp
self.max_retry = max_retry
def __unicode__(self):
return self.u_str.format(self.exp, self.max_retry)
def __str__(self):
return self.__unicode__()
# Define retry util function
def retry_func(func, max_retry=10):
"""
@param func: The function that needs to be retry
@param max_retry: Maximum retry of `func` function, default is `10`
@return: func
@raise: RetryException if retries exceeded than max_retry
"""
for retry in range(1, max_retry + 1):
try:
return func()
except Exception, e:
logger.info('Failed to call {}, in retry({}/{})'.format(func.func,
retry, max_retry))
else:
raise RetryException(e, max_retry)
Use it:
from functools import partial
import requests
def some_request(uri, post):
req = requests.post(uri, post)
return req
uri = 'http://someuri.com'
post = {'test': 'yes'}
try:
retry_func(partial(some_request, uri, post), max_retry=3)
except RetryException, e:
print(e)
Output:
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): someuri.com
INFO:retry:Failed to call <function some_request at 0x7faaba2318c0>, in retry(1/3)
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): someuri.com
INFO:retry:Failed to call <function some_request at 0x7faaba2318c0>, in retry(2/3)
INFO:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): someuri.com
INFO:retry:Failed to call <function some_request at 0x7faaba2318c0>, in retry(3/3)
Exception (HTTPConnectionPool(host='someuri.com', port=80): Max retries exceeded with url: / (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)) raised after 3 tries.
The pattern I use retries a limited number of times, sleeping for a short, exponentially increasing time interval between each attempt, and finally raising the last-seen exception after repeated failure:
def wrappedRequest( self, uri, args ):
lastException = None
interval = 1.0
for _ in range(3):
try:
result = requests.post(uri, args)
return result
except Exception as e:
lastException = e
time.sleep(interval)
interval *= 2.0
raise lastException
(I actually specifically check for HTTPError, URLError, IOError, and BadStatusLine exceptions rather than the broad net of Exception.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With