Add a retry when downloading a file
When downloading of new file fails due to short and temporary network issue then wait a few seconds and retry to download the file again. There were situations when small network issues caused python-tempestconf to end with an error. Story: 2006231 Task: 35832 Change-Id: Ie3f1d8b412dccecac2b05f6b5f540e36824777a4
This commit is contained in:
parent
5cf1410618
commit
041dac5acb
@ -13,9 +13,11 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
from tempest.lib import exceptions
|
from tempest.lib import exceptions
|
||||||
@ -222,6 +224,55 @@ class ImageService(VersionedService):
|
|||||||
with open(path, 'wb') as out:
|
with open(path, 'wb') as out:
|
||||||
out.write(body.data)
|
out.write(body.data)
|
||||||
|
|
||||||
|
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||||
|
"""Retry calling the decorated function using exponential backoff
|
||||||
|
|
||||||
|
http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/
|
||||||
|
original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
|
||||||
|
|
||||||
|
Licensed under the BSD 3-Clause "New" or "Revised" License
|
||||||
|
(https://github.com/saltycrane/retry-decorator/blob/master/LICENSE)
|
||||||
|
|
||||||
|
:param ExceptionToCheck: the exception to check
|
||||||
|
:type ExceptionToCheck: Exception or tuple
|
||||||
|
:param tries: number of times before giving up
|
||||||
|
:type type: int
|
||||||
|
:param delay: initial delay between retries in seconds
|
||||||
|
:type type: int
|
||||||
|
:param backoff: backoff multiplier e.g. value of 2 will double the
|
||||||
|
delay each retry
|
||||||
|
:type backoff: int
|
||||||
|
:param logger: logger to use. If None, print
|
||||||
|
:type logger: logging. Logger instance
|
||||||
|
"""
|
||||||
|
def deco_retry(f):
|
||||||
|
@wraps(f)
|
||||||
|
def f_retry(*args, **kwargs):
|
||||||
|
mtries, mdelay = tries, delay
|
||||||
|
while mtries > 1:
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except ExceptionToCheck as e:
|
||||||
|
msg = "%s, Retrying in %d seconds." % (str(e), mdelay)
|
||||||
|
if logger:
|
||||||
|
logger.warning(msg)
|
||||||
|
else:
|
||||||
|
print(msg)
|
||||||
|
time.sleep(mdelay)
|
||||||
|
mtries -= 1
|
||||||
|
mdelay *= backoff
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
return f_retry
|
||||||
|
return deco_retry
|
||||||
|
|
||||||
|
@retry(urllib.error.URLError, logger=C.LOG)
|
||||||
|
def retry_urlopen(self, url):
|
||||||
|
"""Opens url using urlopen. If it fails, it will try again.
|
||||||
|
|
||||||
|
:type url: string
|
||||||
|
"""
|
||||||
|
return urllib.request.urlopen(url)
|
||||||
|
|
||||||
def _download_file(self, url, destination):
|
def _download_file(self, url, destination):
|
||||||
"""Downloads a file specified by `url` to `destination`.
|
"""Downloads a file specified by `url` to `destination`.
|
||||||
|
|
||||||
@ -232,7 +283,7 @@ class ImageService(VersionedService):
|
|||||||
C.LOG.info("Image '%s' already fetched to '%s'.", url, destination)
|
C.LOG.info("Image '%s' already fetched to '%s'.", url, destination)
|
||||||
return
|
return
|
||||||
C.LOG.info("Downloading '%s' and saving as '%s'", url, destination)
|
C.LOG.info("Downloading '%s' and saving as '%s'", url, destination)
|
||||||
f = urllib.request.urlopen(url)
|
f = self.retry_urlopen(url)
|
||||||
data = f.read()
|
data = f.read()
|
||||||
with open(destination, "wb") as dest:
|
with open(destination, "wb") as dest:
|
||||||
dest.write(data)
|
dest.write(data)
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
When downloading of new file fails due to short and temporary
|
||||||
|
network issue then python-tempestconf does not end immediately
|
||||||
|
with an error but rather waits a few seconds and retries to
|
||||||
|
download the file again.
|
Loading…
Reference in New Issue
Block a user