fix(scheduler): 调度根治——4h 增量只扫活跃对话+账号表进 4h+超时保险丝

用户报「员工列表时间与云客差 2 天」。根因链:4h 增量序列全对话遍历
(WA 9,357 对×~3.5s≈9h,整序列 15h+)超过自身 4h 间隔→与 02:00 全量在
asyncio.Lock 上背靠背互相排队→近两晚全量被挤掉→账号表(仅全量刷)停更
两天,员工列表「数据更新/最新消息时间」显示 09-08 快照。

三层修复:
- 活跃窗:_discover_conversations/群发现加 active_since_ms——已扫过的
  对话仅保留 last_chat_time 在窗内的(云客 lastChatTime 滞后小时级,
  24h 窗足够容错),从未扫过的(新覆盖优先)不受限;陈旧对话无新消息,
  每日 full 兜底。CLI --active-window-hours,四消息实体透传
- 4h 序列头部加 accounts/wa-accounts(~2min)——员工列表时间最多滞后
  4h,不再依赖每晚全量
- 超时保险丝:_page_subprocess 加 timeout(超时 kill 返回 124,上游
  break 下轮补)——messages 各实体 15-80min 预算,单命令拖不死相位;
  full/full-history 不设限

722 测试绿(序列断言 7→9 命令+窗口参数)。干跑验证:近 24h 活跃私聊/
群相对全量降一个数量级(本地旧库群 2011→537;私聊依赖 friends 先刷,
序列顺序已保证)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-10 10:38:47 +08:00
parent 3cf77ec6d5
commit e3fadfe1a6
3 changed files with 162 additions and 72 deletions
+15 -7
View File
@@ -572,7 +572,12 @@ async def test_safe_page_run_full_invokes_bash_full_sync(engine, monkeypatch):
async def test_safe_page_run_messages_builds_scrape_command(engine, monkeypatch):
"""messages job = friends→wa-friends→四类消息→moments 浅扫的命令序列。"""
"""messages job = accounts→friends→四类消息(活跃窗)→moments 浅扫的命令序列。
2026-09-10 调度根治:头部刷员工账号表(员工列表时间最多滞后 4h);
消息实体只扫近 24h 活跃对话(--active-window-hours 24,防序列 15h+
挤死 full);陈旧对话每日 full 兜底。
"""
sched = SyncScheduler(engine=engine, max_conversations_per_run=123)
commands: list[list[str]] = []
@@ -584,22 +589,25 @@ async def test_safe_page_run_messages_builds_scrape_command(engine, monkeypatch)
await sched._safe_page_run("messages")
# 2026-08-21: messages job 是 friends→wa-friends→四类消息的命令序列,
# 每条都调 scrape_via_page.py;2026-08-25 末尾追加 moments 浅扫
assert len(commands) == 7
assert len(commands) == 9
for args in commands:
assert args[1].endswith("scrape_via_page.py")
def entity_of(args: list[str]) -> str:
return args[args.index("--entity") + 1]
assert entity_of(commands[0]) == "friends"
assert entity_of(commands[1]) == "wa-friends"
for args in commands[2:6]:
# 头部:账号刷新(员工列表「数据更新/最新消息时间」来源)
assert entity_of(commands[0]) == "accounts"
assert entity_of(commands[1]) == "wa-accounts"
assert entity_of(commands[2]) == "friends"
assert entity_of(commands[3]) == "wa-friends"
# 四类消息:24h 活跃窗(2026-09-10 根治调度堵塞)
for args in commands[4:8]:
assert entity_of(args) in (
"messages", "wa-messages", "group-messages", "wa-group-messages",
)
assert args[args.index("--max-conversations") + 1] == "99999"
assert args[args.index("--active-window-hours") + 1] == "24"
# moments 浅扫在序列末尾:每员工最多 3 页
moments_cmd = commands[-1]
assert entity_of(moments_cmd) == "moments"