From 3cfbfb54e12c93aefe33af10f9167a43fc6c3207 Mon Sep 17 00:00:00 2001 From: Hommy Date: Sat, 22 Aug 2026 22:07:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E9=87=8D=E8=AF=95=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=E4=B8=BA10=E6=AC=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/draft_downloader.py | 19 +++++++++---------- tests/test_draft_download_failure_kind.py | 4 ++-- tests/test_draft_download_resume.py | 1 + .../test_draft_downloader_remote_materials.py | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/utils/draft_downloader.py b/src/utils/draft_downloader.py index 3d9b022..2b8a6a6 100644 --- a/src/utils/draft_downloader.py +++ b/src/utils/draft_downloader.py @@ -207,7 +207,7 @@ def _localize_draft_meta_info(target_dir: str, draft_id: str) -> None: _REQUEST_CONNECT_TIMEOUT = 10 _REQUEST_READ_TIMEOUT = 30 -_MAX_RETRIES = 5 +_MAX_RETRIES = 10 _REQUEST_HEADERS = { "User-Agent": ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " @@ -818,14 +818,13 @@ def download_single_file(file_url: str, target_dir: str) -> bool: def _download_single_file(file_url: str, target_dir: str) -> None: """下载单个文件;失败时抛出 DraftDownloadAbort。""" - max_retries = 5 retry_count = 0 full_file_path, url_draft_id = _resolve_download_target_path(file_url, target_dir) # 仅视频/图片/音频走 Range 续传;json 等仍每次整文件覆盖下载。 enable_resume = _is_media_resource(file_url) or _is_media_resource(full_file_path) - while retry_count <= max_retries: + while retry_count <= _MAX_RETRIES: try: extra_headers = None resume_from = 0 @@ -863,17 +862,17 @@ def _download_single_file(file_url: str, target_dir: str) -> None: http_status=status, ) retry_count += 1 - if retry_count > max_retries: + if retry_count > _MAX_RETRIES: status = response.status_code logger.error( "Transient HTTP %s, download failed after %s retries, URL: %s", status, - max_retries, + _MAX_RETRIES, file_url, ) _abort( DraftDownloadFailureKind.NETWORK_RETRY_EXHAUSTED, - detail=f"HTTP {status} after {max_retries} retries", + detail=f"HTTP {status} after {_MAX_RETRIES} retries", url=file_url, http_status=status, ) @@ -881,7 +880,7 @@ def _download_single_file(file_url: str, target_dir: str) -> None: "Transient HTTP %s, retry (%s/%s), URL: %s", response.status_code, retry_count, - max_retries, + _MAX_RETRIES, file_url, ) _sleep_transient_http_backoff(retry_count, response) @@ -916,9 +915,9 @@ def _download_single_file(file_url: str, target_dir: str) -> None: url=file_url, ) retry_count += 1 - if retry_count > max_retries: + if retry_count > _MAX_RETRIES: logger.error( - f"Network error, download failed after {max_retries} retries: {e}, URL: {file_url}" + f"Network error, download failed after {_MAX_RETRIES} retries: {e}, URL: {file_url}" ) _abort( DraftDownloadFailureKind.NETWORK_RETRY_EXHAUSTED, @@ -926,7 +925,7 @@ def _download_single_file(file_url: str, target_dir: str) -> None: url=file_url, ) logger.warning( - f"Network error, retry ({retry_count}/{max_retries}): {e}, URL: {file_url}" + f"Network error, retry ({retry_count}/{_MAX_RETRIES}): {e}, URL: {file_url}" ) _sleep_network_retry_backoff() except OSError as e: diff --git a/tests/test_draft_download_failure_kind.py b/tests/test_draft_download_failure_kind.py index 88bc809..9311ed1 100644 --- a/tests/test_draft_download_failure_kind.py +++ b/tests/test_draft_download_failure_kind.py @@ -136,7 +136,7 @@ class TestDownloadSingleFileFailureKind: dd._download_single_file(self._URL, "/tmp/unused") assert ei.value.kind == dd.DraftDownloadFailureKind.NETWORK_RETRY_EXHAUSTED assert ei.value.http_status == 503 - assert m_req.get.call_count == 6 + assert m_req.get.call_count == dd._MAX_RETRIES + 1 def test_timeout_exhausted_is_network_retry_exhausted(self, no_sleep) -> None: with patch.object(dd, "requests") as m_req: @@ -145,7 +145,7 @@ class TestDownloadSingleFileFailureKind: with pytest.raises(dd.DraftDownloadAbort) as ei: dd._download_single_file(self._URL, "/tmp/unused") assert ei.value.kind == dd.DraftDownloadFailureKind.NETWORK_RETRY_EXHAUSTED - assert m_req.get.call_count == 6 + assert m_req.get.call_count == dd._MAX_RETRIES + 1 def test_connection_refused_is_resource_unavailable(self, no_sleep) -> None: with patch.object(dd, "requests") as m_req: diff --git a/tests/test_draft_download_resume.py b/tests/test_draft_download_resume.py index cbe2b70..e53ba33 100644 --- a/tests/test_draft_download_resume.py +++ b/tests/test_draft_download_resume.py @@ -290,3 +290,4 @@ class TestDownloadRemoteFileResume: assert "Range" not in (m_req.get.call_args_list[1].kwargs.get("headers") or {}) with open(out, "rb") as f: assert f.read() == b"ZZZ" + diff --git a/tests/test_draft_downloader_remote_materials.py b/tests/test_draft_downloader_remote_materials.py index 376c78f..4b74134 100644 --- a/tests/test_draft_downloader_remote_materials.py +++ b/tests/test_draft_downloader_remote_materials.py @@ -485,7 +485,7 @@ class TestDownloadSingleFile: resp.close.assert_called_once() def test_gateway_503_retries_until_exhausted(self, no_sleep) -> None: - """503 退避重试,耗尽后与网络重试一致共 6 次请求。""" + """503 退避重试,耗尽后与网络重试一致共 _MAX_RETRIES+1 次请求。""" file_url = f"{self._BASE}/app/output/draft/20251204214904ccb1af38/x.bin" with tempfile.TemporaryDirectory() as td: resp = self._stream_response([], status=503) @@ -493,8 +493,8 @@ class TestDownloadSingleFile: m_req.get.return_value = resp m_req.exceptions = requests.exceptions assert dd.download_single_file(file_url, td) is False - assert m_req.get.call_count == 6 - assert resp.close.call_count == 6 + assert m_req.get.call_count == dd._MAX_RETRIES + 1 + assert resp.close.call_count == dd._MAX_RETRIES + 1 def test_retries_then_success_on_read_timeout(self, no_sleep) -> None: calls: list = [] @@ -540,8 +540,8 @@ class TestDownloadSingleFile: m_req.get.side_effect = requests.exceptions.ConnectionError("down") m_req.exceptions = requests.exceptions assert dd.download_single_file(file_url, td) is False - # retry_count 0..5 共 6 次尝试后放弃(与原先 max_retries=5 语义一致) - assert m_req.get.call_count == 6 + # retry_count 0.._MAX_RETRIES 共 _MAX_RETRIES+1 次尝试后放弃 + assert m_req.get.call_count == dd._MAX_RETRIES + 1 @patch.object(dd, "_update_json_file_paths") def test_plain_file_does_not_touch_json_paths(self, m_upd, no_sleep) -> None: