feat(sites): auto-screenshot on final download failure for debugging
所有站点 with_retry 在最后一次重试失败、reset 之前自动截图, 保存到 logs/screenshots/。网页站点走 Playwright page.screenshot(), 安能走 CDP Page.captureScreenshot。截图失败绝不阻塞任务流程。 - paths.py: 新增 SCREENSHOT_DIR (BASE_DIR/logs/screenshots/) - runtime.py: 新增 capture_error_screenshot() 工具函数 - .gitignore: 新增 logs/ 忽略规则 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,10 +11,11 @@ from inbound_verify.paths import DOWNLOAD_DIR, CONFIG_PATH
|
||||
from inbound_verify import state_store
|
||||
|
||||
|
||||
def with_retry(site_name, label, flow, reset, max_attempts=3):
|
||||
def with_retry(site_name, label, flow, reset, max_attempts=3, page=None):
|
||||
"""异常兜底:flow 失败 → 重置回初始态 → 重试,最多 max_attempts 次(含首次)。
|
||||
|
||||
每次失败都重置(含最终放弃那一次):既是重试前的清场,也保证最终放弃时环境干净。
|
||||
最后一次失败时(重置前)自动截图保存到 logs/screenshots/,供问题排查。
|
||||
flow 为零参可调用;返回 False 视为失败,其余视为成功。
|
||||
返回 True=最终成功,False=重试耗尽放弃(供调度层判断任务成败)。
|
||||
"""
|
||||
@@ -28,6 +29,13 @@ def with_retry(site_name, label, flow, reset, max_attempts=3):
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"⚠️ 【{site_name}-{label}】第 {attempt}/{max_attempts} 次失败: {e}")
|
||||
if attempt == max_attempts and page is not None:
|
||||
try:
|
||||
from inbound_verify.runtime import capture_error_screenshot
|
||||
|
||||
capture_error_screenshot(page, site_name, label, attempt, str(e))
|
||||
except Exception:
|
||||
pass
|
||||
print(f" → 重置【{site_name}】到初始态,清理环境 ...")
|
||||
try:
|
||||
reset()
|
||||
@@ -163,6 +171,7 @@ def zto_expected_download(page, force=False, date=None):
|
||||
"应到",
|
||||
lambda: zto_expected_download_impl(page, force=force, date=date),
|
||||
lambda: zto_reset(page),
|
||||
page=page,
|
||||
)
|
||||
|
||||
|
||||
@@ -209,14 +218,10 @@ def zto_expected_download_impl(page, force=False, date=None):
|
||||
if target_cell is None:
|
||||
print(" ℹ️ 目标日期不在当前视窗,正在翻月导航 ...")
|
||||
if not _zto_flip_to_target_month(ewb_frame, page, target_time):
|
||||
raise RuntimeError(
|
||||
f"翻月后仍无法定位目标日期格子(time={target_time})"
|
||||
)
|
||||
raise RuntimeError(f"翻月后仍无法定位目标日期格子(time={target_time})")
|
||||
target_cell = _zto_find_visible_day(ewb_frame, target_time)
|
||||
if target_cell is None:
|
||||
raise RuntimeError(
|
||||
f"翻月后仍无法定位目标日期格子(time={target_time})"
|
||||
)
|
||||
raise RuntimeError(f"翻月后仍无法定位目标日期格子(time={target_time})")
|
||||
|
||||
# 日期格子用 _dom_click 直接派发事件:.click() 会先 hover 格子,触发
|
||||
# "范围长度"提示气泡(.date-range-length-tip)盖住格子导致点击被遮挡超时。
|
||||
@@ -413,6 +418,7 @@ def zto_actual_download(page, force=False, date=None):
|
||||
"实到",
|
||||
lambda: zto_actual_download_impl(page, date=date),
|
||||
lambda: zto_reset(page),
|
||||
page=page,
|
||||
)
|
||||
|
||||
|
||||
@@ -458,14 +464,10 @@ def zto_actual_download_impl(page, date=None):
|
||||
if target_cell is None:
|
||||
print(" ℹ️ 目标日期不在当前视窗,正在翻月导航 ...")
|
||||
if not _zto_flip_to_target_month(arr_frame, page, target_time):
|
||||
raise RuntimeError(
|
||||
f"翻月后仍无法定位目标日期格子(time={target_time})"
|
||||
)
|
||||
raise RuntimeError(f"翻月后仍无法定位目标日期格子(time={target_time})")
|
||||
target_cell = _zto_find_visible_day(arr_frame, target_time)
|
||||
if target_cell is None:
|
||||
raise RuntimeError(
|
||||
f"翻月后仍无法定位目标日期格子(time={target_time})"
|
||||
)
|
||||
raise RuntimeError(f"翻月后仍无法定位目标日期格子(time={target_time})")
|
||||
|
||||
# 日期格子用 _dom_click 直接派发事件:Playwright 的 .click() 会先 hover 格子,
|
||||
# 触发"范围长度"提示气泡(.date-range-length-tip)盖住格子,导致点击被判遮挡而超时。
|
||||
|
||||
Reference in New Issue
Block a user