feat: 选择器健康检测 - 连续未命中自动上报,暴露"静默空转"
通用任务 click 步骤连续 10 次找不到元素时判定选择器可能失效(App 改版), 记录 last_warning 并日志 ERROR,监控页设备行显示 ⚠ 警告。 解决"选择器失效但任务仍显示成功"的静默空转问题。
This commit is contained in:
@@ -83,6 +83,25 @@ class GenericStepsWorker(BaseWorker):
|
||||
self.max_duration = int(p.get("max_duration", 0))
|
||||
self.steps = p.get("steps", [])
|
||||
self._action_counts = {} # 步骤执行计数 {step_label: count}
|
||||
self._miss_counts = {} # 选择器健康:selector -> 连续未命中次数
|
||||
|
||||
# 某 click 选择器连续未找到元素的次数达到该值,判定可能失效(App 改版)
|
||||
_MAX_CONSECUTIVE_MISS = 10
|
||||
|
||||
def _track_selector_health(self, sel_val, found):
|
||||
"""记录某选择器的连续未命中次数,达到阈值上报 last_warning 并重置计数。
|
||||
|
||||
用于发现"选择器失效但任务仍显示成功"的静默空转问题(如 App 改版后元素找不到了)。
|
||||
"""
|
||||
if found:
|
||||
self._miss_counts.pop(sel_val, None)
|
||||
return
|
||||
n = self._miss_counts.get(sel_val, 0) + 1
|
||||
self._miss_counts[sel_val] = n
|
||||
if n >= self._MAX_CONSECUTIVE_MISS:
|
||||
_log.error(f"[{self.serial}] 选择器连续 {n} 次未找到元素,可能已失效(App 改版?):{sel_val}")
|
||||
_update_status(self.serial, last_warning=f"选择器连续{n}次未命中")
|
||||
self._miss_counts.pop(sel_val, None) # 已上报,重置避免刷屏
|
||||
|
||||
def run_task(self, d):
|
||||
"""按 steps 顺序执行。loop 步骤递归执行其 children。"""
|
||||
@@ -179,6 +198,7 @@ class GenericStepsWorker(BaseWorker):
|
||||
# 兼容旧配置:selector_type 不是 xpath 但值是 XPath(以 // 开头)
|
||||
if sel_type != "xpath" and sel_val.strip().startswith("//"):
|
||||
sel_type = "xpath"
|
||||
found = False
|
||||
try:
|
||||
if sel_type == "xpath":
|
||||
# u2 的 d.xpath() 返回 XPathSelector,exists 是属性需用 wait()
|
||||
@@ -186,6 +206,7 @@ class GenericStepsWorker(BaseWorker):
|
||||
if el.wait(timeout=timeout):
|
||||
el.click()
|
||||
_log.info(f"[{self.serial}] click 命中: xpath={sel_val}")
|
||||
found = True
|
||||
else:
|
||||
_log.warning(f"[{self.serial}] click 未找到元素: xpath={sel_val} (等待{timeout}s)")
|
||||
else:
|
||||
@@ -194,8 +215,10 @@ class GenericStepsWorker(BaseWorker):
|
||||
if el.exists(timeout=timeout):
|
||||
el.click()
|
||||
_log.info(f"[{self.serial}] click 命中: {sel_type}={sel_val}")
|
||||
found = True
|
||||
else:
|
||||
_log.warning(f"[{self.serial}] click 未找到元素: {sel_type}={sel_val} (等待{timeout}s)")
|
||||
self._track_selector_health(sel_val, found)
|
||||
except Exception as e:
|
||||
_log.warning(f"[{self.serial}] click 异常: {e}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user