From a71924ca1a4070b0bd4129c2c19a56cc97847073 Mon Sep 17 00:00:00 2001 From: Misaka Date: Tue, 14 Jul 2026 22:24:41 +0800 Subject: [PATCH] Cap export-task poll loops at 5min to avoid infinite hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 顺心/中通/韵达/安能 的导出任务轮询循环原本只在"本批任务全部完成"时 退出,无任何时间上限:任务卡在生成中、或因时钟偏移没落进 40s 容差窗口 匹配不上时,会无限轮询、流程永不返回,连 with_retry 都没机会触发。 给这 5 处轮询加 300s deadline,超时即 raise → 流程返回 False → 触发 已有的重置重试机制。把"永久挂死"变成"有界失败→自动重试"。 Co-Authored-By: Claude --- site_anneng.py | 7 +++++++ site_shunxin.py | 15 +++++++++++++++ site_yunda.py | 8 ++++++++ site_zto.py | 8 ++++++++ 4 files changed, 38 insertions(+) diff --git a/site_anneng.py b/site_anneng.py index 6863d75..26e7d75 100644 --- a/site_anneng.py +++ b/site_anneng.py @@ -702,7 +702,14 @@ def poll_and_download_tasks(export_cdp, export_times, download_dir): total_expected = len(export_times) print(f">> 轮询导出下载任务(期望 {total_expected} 个)...") + poll_deadline = ( + time.monotonic() + 300 + ) # 5 分钟上限:任务卡死/匹配不上时超时失败,交由上层重置重试 while True: + if time.monotonic() > poll_deadline: + raise RuntimeError( + "轮询导出任务超时(5 分钟未全部完成/匹配),疑似任务卡死" + ) wait_until( export_cdp, "!!document.querySelector('.ant-table-thead')", diff --git a/site_shunxin.py b/site_shunxin.py index 5a6df56..e33d009 100644 --- a/site_shunxin.py +++ b/site_shunxin.py @@ -2,6 +2,7 @@ import os import re +import time import yaml from datetime import datetime, timedelta import pandas as pd @@ -249,7 +250,14 @@ def shunxin_expected_download_impl(page): # 7. 轮询任务状态 print(">> 列表已加载,开始匹配并检查任务状态...") + poll_deadline = ( + time.monotonic() + 300 + ) # 5 分钟上限:任务卡死/匹配不上时超时失败,交由上层重置重试 while True: + if time.monotonic() > poll_deadline: + raise RuntimeError( + "轮询导出任务超时(5 分钟未全部完成/匹配),疑似任务卡死" + ) rows = page.locator(".ant-table-tbody > tr.ant-table-row") row_count = rows.count() pending_tasks = 0 @@ -506,7 +514,14 @@ def shunxin_actual_download_impl(page): # 6. 轮询任务状态 print(">> 列表已加载,开始匹配并检查任务状态...") + poll_deadline = ( + time.monotonic() + 300 + ) # 5 分钟上限:任务卡死/匹配不上时超时失败,交由上层重置重试 while True: + if time.monotonic() > poll_deadline: + raise RuntimeError( + "轮询导出任务超时(5 分钟未全部完成/匹配),疑似任务卡死" + ) rows = page.locator(".ant-table-tbody > tr.ant-table-row") row_count = rows.count() pending_tasks = 0 diff --git a/site_yunda.py b/site_yunda.py index bc3f5fb..8186a1b 100644 --- a/site_yunda.py +++ b/site_yunda.py @@ -2,6 +2,7 @@ import os import re +import time import yaml from datetime import datetime, timedelta import pandas as pd @@ -602,7 +603,14 @@ def _yunda_poll_and_download_tasks(page, export_times, download_dir, final_filen print(">> 开始轮询离线任务队列,直到全部完成...") total_expected = len(export_times) + poll_deadline = ( + time.monotonic() + 300 + ) # 5 分钟上限:任务卡死/匹配不上时超时失败,交由上层重置重试 while True: + if time.monotonic() > poll_deadline: + raise RuntimeError( + "轮询导出任务超时(5 分钟未全部完成/匹配),疑似任务卡死" + ) task_rows = export_ws_frame.locator( ".datagrid-view2 .datagrid-btable tbody tr.datagrid-row" ) diff --git a/site_zto.py b/site_zto.py index 3037092..a070132 100644 --- a/site_zto.py +++ b/site_zto.py @@ -2,6 +2,7 @@ import os import re +import time import yaml from datetime import datetime import pandas as pd @@ -496,7 +497,14 @@ def _zto_poll_and_download_tasks(page, export_times, download_dir, final_filenam print(">> 列表已加载,开始匹配并检查任务状态...") total_expected = len(export_times) + poll_deadline = ( + time.monotonic() + 300 + ) # 5 分钟上限:任务卡死/匹配不上时超时失败,交由上层重置重试 while True: + if time.monotonic() > poll_deadline: + raise RuntimeError( + "轮询导出任务超时(5 分钟未全部完成/匹配),疑似任务卡死" + ) task_rows = taskdone_frame.locator( "#taskdoneDatagrid .mini-grid-rows-view .mini-grid-row" )