Flow 作者指南
Flow 是任務的反應式場景監督器。它在中斷、節點動作失敗和未知畫面後重新觀察螢幕, 不恢復舊呼叫棧。
它不負責業務點選、路線規劃或跨任務頁面導航。節點 action 繼續使用任務原有的 wait_until、wait_click_confirm 和輸入 helper。
最小接入
BaseNTETask 已為每個 Task 單例建立 self.flow, 重新整理幀, 註冊月卡中斷, 並讓 Flow 執行期間的 wait_until() 自動成為安全點。任務只需要宣告自己的場景:
class Node(Enum):
READY = "ready"
RESULT = "result"
TEAM = "team"
def _configure_flow(self):
self.flow.node(Node.RESULT, self.has_result, self._on_result)
self.flow.node(Node.READY, self.is_ready, self._on_ready)
self.flow.node(Node.TEAM, self.is_in_team, self._enter_task)
self.flow.fallback(self._press_escape_for_recovery, timeout=360)
在任務入口中執行它:
completed = self.flow.loop(
lambda: self._session.is_finished,
on_error=self._handle_flow_error,
poll_interval=0.1,
)
節點 action 契約
- detector 必須是無副作用的當前畫面判斷。優先順序只用於 detector 同時命中時的消歧, 預設按註冊順序。
- action 可能在畫面持續可見時重複執行。它必須冪等, 或使用已有的
interval/wait_until節流, 不能假定每次 action 都會立刻切換頁面。 - action 的返回值不參與轉移判斷; Flow 只根據下一次畫面檢測決定下一步。
- 可恢復的業務失敗丟擲既有異常, 通常是
WaitFailedException。Flow 重新整理畫面後先檢查原節點: 原節點仍在才交給on_error; 原節點消失就直接重新分類。 - 自定義高頻迴圈中呼叫
self.flow.safe_point()。它發現中斷會丟擲FlowReplan; 如 action 需要記錄本輪狀態, 記錄後必須繼續丟擲它。
try:
self._control_until_finished()
except FlowReplan:
session.interrupted_control_round = session.round_index
raise
不要在任務程式碼中呼叫 Flow 的內部中斷檢查。普通等待已經自動檢查; 自定義迴圈只使用 safe_point()。
中斷與恢復語義
- 中斷 handler 返回非
False表示已處理。Flow 丟棄舊呼叫棧, 先觀察原節點。 - 原節點在中斷後暫時未匹配時, Flow 最多等待 3 秒; 期間重新匹配則繼續原節點, 超時後才全量分類。
- handler 返回
False表示處理失敗。Flow 不會繼續舊 action, 而是立即執行 fallback, 不會重複執行該 handler 後才恢復。 - 允許 handler 返回
False的 Flow 必須註冊 fallback; 否則loop()會失敗而不是冒險繼續舊 action。 - 未識別畫面會先容忍 5 秒; 之後反覆執行 fallback; 達到任務配置的 fallback timeout 才失敗。
TaskDisabledException是控制流, 會直接離開 Flow, 不會被恢復邏輯吞掉。