feat(cookie-gate): 调度器恢复重跑接线与控制台健康自检

调度器维护循环挂载 CookieGateRecoveryManager,登录态恢复后按原业务日期自动
重跑被阻断工作流并飞书确认;工作流级 required_accounts 声明接入目录解析;
采集器抛 CookieExpiredError 退出 75;控制台新增 /api/health 自检端点与进程内
看门狗,配合 deploy/watchdog 双层保活;安装脚本同步。
This commit is contained in:
wangyunlong committed 2026-10-09 13:45:29 +08:00
1 parent 78ea4641ce
commit 130f06b320
13 files changed
+318 -77

No files matched your search

+16
View File
@@ -79,6 +79,10 @@ class WorkflowEntry:
steps: tuple[WorkflowStepEntry, ...] = ()
notification_workflow_id: str | None = None
topic_config: WorkflowTopicConfig | None = None
# Orchestrator entries whose own binding carries no runtime account while
# the spawned child collectors do; the cookie gate probes these before
# the workflow runs.
required_accounts: tuple[str, ...] = ()
@dataclass(frozen=True, slots=True)
@@ -218,6 +222,9 @@ def _parse_workflow(item: Any) -> WorkflowEntry:
if trigger == "scheduled" and (not isinstance(task_name, str) or not task_name):
raise CatalogError(f"scheduled workflow requires source task name: {workflow_id}")
topic_config = _parse_topic_config(item.get("topic_config"), workflow_id)
required_accounts = _parse_required_accounts(
item.get("required_accounts", []), workflow_id
)
return WorkflowEntry(
workflow_id=workflow_id,
module=module,
@@ -229,9 +236,18 @@ def _parse_workflow(item: Any) -> WorkflowEntry:
note=item.get("note"),
steps=steps,
topic_config=topic_config,
required_accounts=required_accounts,
)
def _parse_required_accounts(value: Any, workflow_id: str) -> tuple[str, ...]:
if not isinstance(value, list) or not all(
isinstance(item, str) and _WORKFLOW_ID.fullmatch(item) for item in value
):
raise CatalogError(f"invalid required_accounts for {workflow_id}")
return tuple(dict.fromkeys(value))
def _parse_topic_config(value: Any, workflow_id: str) -> WorkflowTopicConfig | None:
if value is None:
return None