Skip to content

Commit aae1502

Browse files
committed
fix: 截图失败退避未生效,拆 screencap 链式调用检测 job.failed
post_screencap().wait().get() 链式调用中 wait() 只阻塞不检查状态,C++ 层 screencap failed 时 cached_image 仍返回空/旧图且不抛异常,导致 except 永远不触发、5s 退避形同虚设(见 maafw.log 6.8 万行连续刷屏)。 拆开后显式判 job.failed + 防御空图 (0,0,3),让 except 真正能抓到失败。退避参数提取为模块常量,新增持续退避期的周期日志(每 60 次失败一条,约 5min)。
1 parent 8837b3b commit aae1502

2 files changed

Lines changed: 37 additions & 8 deletions

File tree

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,8 @@ Thumbs.db
5454
*.swp
5555
*~
5656
*.code-workspace
57+
58+
# Agent
59+
.omo/
60+
.claude/
61+
.codex/

aao/measure/worker.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
if TYPE_CHECKING:
2121
from maa.controller import Win32Controller
2222

23+
# 退避参数:前 _FAST_RETRY_THRESHOLD 次快速重试(检测瞬断),
24+
# 之后按 _BACKOFF_S 间隔重试(游戏可能已退出/最小化,无需高频截图)。
25+
_FAST_RETRY_THRESHOLD = 3
26+
_BACKOFF_S = 5.0 # 连续失败退避间隔(用户要求 5-10s)
27+
_PERIODIC_LOG_EVERY = 60 # 持续退避中每 N 次失败输出一条进度日志(≈5min 一条)
28+
2329

2430
class MeasurementWorker(QObject):
2531
"""采集循环 worker(moveToThread 到 QThread 运行)。"""
@@ -57,20 +63,38 @@ def run(self) -> None:
5763
self._reset_requested = False
5864
self.time_source.reset_timer()
5965
try:
60-
img = self.controller.post_screencap().wait().get()
66+
# 拆开链式调用: wait() 只阻塞不检查状态,需显式判 job.failed。
67+
# 否则 C++ 层 screencap failed 时 cached_image 仍返回空/旧图、不抛异常,
68+
# 导致 except 永远不触发、退避不生效(见 maafw.log 连续刷屏问题)。
69+
job = self.controller.post_screencap()
70+
job.wait()
71+
if job.failed:
72+
raise RuntimeError("screencap job failed")
73+
img = job.get()
74+
# 防御: MaaFW 有时返回 (0,0,3) 空数组而非抛异常
75+
if img is None or img.size == 0: # pyright: ignore[reportUnnecessaryComparison]
76+
raise RuntimeError("screencap returned empty image")
6177
self.time_source.update(img)
6278
self._consecutive_errors = 0
6379
except Exception:
6480
self._consecutive_errors += 1
65-
if self._consecutive_errors <= 3:
66-
logger.warning("截图失败 %d 次", self._consecutive_errors)
67-
elif self._consecutive_errors == 4:
81+
n = self._consecutive_errors
82+
if n <= _FAST_RETRY_THRESHOLD:
83+
logger.warning("截图失败 %d 次", n)
84+
elif n == _FAST_RETRY_THRESHOLD + 1:
6885
logger.error(
69-
"截图连续失败 %d 次, 游戏可能已退出或最小化, 降低重试频率",
70-
self._consecutive_errors,
86+
"截图连续失败 %d 次, 游戏可能已退出或最小化, 降低重试频率至 %.0fs",
87+
n,
88+
_BACKOFF_S,
89+
)
90+
elif n % _PERIODIC_LOG_EVERY == 0:
91+
logger.warning(
92+
"截图仍连续失败 (%d 次), 每 %.0fs 重试一次",
93+
n,
94+
_BACKOFF_S,
7195
)
72-
# 退避: 前 3 次快重试, 之后 5s 一次
73-
backoff = self.interval_s if self._consecutive_errors <= 3 else 5.0
96+
# 退避: 前 N 次快重试, 之后 _BACKOFF_S 一次
97+
backoff = self.interval_s if n <= _FAST_RETRY_THRESHOLD else _BACKOFF_S
7498
time.sleep(backoff)
7599
continue
76100

0 commit comments

Comments
 (0)