From 23822e2e3f95d6a64a57e2e39047ddf2eda2bc5d Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Wed, 17 Jun 2020 16:03:49 +0800 Subject: [PATCH] ci: retry download if catched IOError/EOFError --- tools/ci/python_packages/gitlab_api.py | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/ci/python_packages/gitlab_api.py b/tools/ci/python_packages/gitlab_api.py index e7eced284..561ffb863 100644 --- a/tools/ci/python_packages/gitlab_api.py +++ b/tools/ci/python_packages/gitlab_api.py @@ -4,6 +4,7 @@ import argparse import tempfile import tarfile import zipfile +from functools import wraps import gitlab @@ -11,6 +12,8 @@ import gitlab class Gitlab(object): JOB_NAME_PATTERN = re.compile(r"(\w+)(\s+(\d+)/(\d+))?") + DOWNLOAD_ERROR_MAX_RETRIES = 3 + def __init__(self, project_id=None): config_data_from_env = os.getenv("PYTHON_GITLAB_CONFIG") if config_data_from_env: @@ -64,6 +67,31 @@ class Gitlab(object): with zipfile.ZipFile(temp_file.name, "r") as archive_file: archive_file.extractall(destination) + def retry_download(func): + """ + This wrapper will only catch IOError and retry the whole function. + + So only use it with download functions, read() inside and atomic + functions + """ + @wraps(func) + def wrapper(self, *args, **kwargs): + retried = 0 + while True: + try: + res = func(self, *args, **kwargs) + except (IOError, EOFError) as e: + retried += 1 + if retried > self.DOWNLOAD_ERROR_MAX_RETRIES: + raise e # get out of the loop + else: + print('Retried for the {} time'.format(retried)) + continue + else: + break + return res + return wrapper + def download_artifact(self, job_id, artifact_path, destination=None): """ download specific path of job artifacts and extract to destination. @@ -118,6 +146,7 @@ class Gitlab(object): job_id_list.append({"id": job.id, "parallel_num": match.group(3)}) return job_id_list + @retry_download def download_archive(self, ref, destination, project_id=None): """ Download archive of certain commit of a repository and extract to destination path