Merge "Consolidate retry code in functest client"

This commit is contained in:
Zuul
2019-02-06 18:32:38 +00:00
committed by Gerrit Code Review

View File

@@ -48,12 +48,13 @@ class RequestError(Exception):
class ResponseError(Exception): class ResponseError(Exception):
def __init__(self, response, method=None, path=None): def __init__(self, response, method=None, path=None, details=None):
self.status = response.status self.status = response.status
self.reason = response.reason self.reason = response.reason
self.method = method self.method = method
self.path = path self.path = path
self.headers = response.getheaders() self.headers = response.getheaders()
self.details = details
for name, value in self.headers: for name, value in self.headers:
if name.lower() == 'x-trans-id': if name.lower() == 'x-trans-id':
@@ -68,8 +69,11 @@ class ResponseError(Exception):
return repr(self) return repr(self)
def __repr__(self): def __repr__(self):
return '%d: %r (%r %r) txid=%s' % ( msg = '%d: %r (%r %r) txid=%s' % (
self.status, self.reason, self.method, self.path, self.txid) self.status, self.reason, self.method, self.path, self.txid)
if self.details:
msg += '\n%s' % self.details
return msg
def listing_empty(method): def listing_empty(method):
@@ -299,6 +303,16 @@ class Connection(object):
self.connection.request(method, path, data, headers) self.connection.request(method, path, data, headers)
return self.connection.getresponse() return self.connection.getresponse()
try:
self.response = self.request_with_retry(try_request)
except RequestError as e:
details = "{method} {path} headers: {headers} data: {data}".format(
method=method, path=path, headers=headers, data=data)
raise RequestError('Unable to complete request: %s.\n%s' % (
details, str(e)))
return self.response.status
def request_with_retry(self, try_request):
self.response = None self.response = None
try_count = 0 try_count = 0
fail_messages = [] fail_messages = []
@@ -307,6 +321,9 @@ class Connection(object):
try: try:
self.response = try_request() self.response = try_request()
except socket.timeout as e:
fail_messages.append(safe_repr(e))
continue
except http_client.HTTPException as e: except http_client.HTTPException as e:
fail_messages.append(safe_repr(e)) fail_messages.append(safe_repr(e))
continue continue
@@ -320,17 +337,13 @@ class Connection(object):
if try_count != 5: if try_count != 5:
time.sleep(5) time.sleep(5)
continue continue
break break
if self.response: if self.response:
return self.response.status return self.response
request = "{method} {path} headers: {headers} data: {data}".format( raise RequestError('Attempts: %s, Failures: %s' % (
method=method, path=path, headers=headers, data=data) len(fail_messages), fail_messages))
raise RequestError('Unable to complete http request: %s. '
'Attempts: %s, Failures: %s' %
(request, len(fail_messages), fail_messages))
def put_start(self, path, hdrs=None, parms=None, cfg=None, chunked=False): def put_start(self, path, hdrs=None, parms=None, cfg=None, chunked=False):
if hdrs is None: if hdrs is None:
@@ -1026,11 +1039,12 @@ class File(Base):
headers = self.make_headers(cfg=cfg) headers = self.make_headers(cfg=cfg)
headers.update(hdrs) headers.update(hdrs)
for _attempt in range(3): def try_request():
# rewind to be ready for another attempt
data.seek(0)
self.conn.put_start(self.path, hdrs=headers, parms=parms, cfg=cfg) self.conn.put_start(self.path, hdrs=headers, parms=parms, cfg=cfg)
transferred = 0 transferred = 0
try:
for buff in iter(lambda: data.read(block_size), b''): for buff in iter(lambda: data.read(block_size), b''):
self.conn.put_data(buff) self.conn.put_data(buff)
transferred += len(buff) transferred += len(buff)
@@ -1038,14 +1052,14 @@ class File(Base):
callback(transferred, self.size) callback(transferred, self.size)
self.conn.put_end() self.conn.put_end()
except socket.timeout as err: return self.conn.response
raise err
if is_success(self.conn.response.status): try:
break self.response = self.conn.request_with_retry(try_request)
# else, rewind to be ready for another attempt except RequestError as e:
data.seek(0) raise ResponseError(self.conn.response, 'PUT',
else: self.conn.make_path(self.path), details=str(e))
if not is_success(self.response.status):
raise ResponseError(self.conn.response, 'PUT', raise ResponseError(self.conn.response, 'PUT',
self.conn.make_path(self.path)) self.conn.make_path(self.path))