微信推送断供 24 小时:会话死透 -14,ntfy 顶上补发

早上第一推就报限流

K1 交易报告一天推两轮微信,11:20 午盘这轮挂了。hermes send --to weixin 抛出一行熟得不能再熟的错:iLink sendmessage rate limited; cooldown active for 30.0s。老规矩,睡 35 秒重试,原样。再试,原样。

昨天刚查过一轮,结论是 token 过期不是限流。今天这错横跨好几分钟、好几个全新进程都甩同一个 cooldown active,不对劲——熔断是进程内存态,新起的进程首调应该直接打到服务端,不该上来就"冷却中"。

别猜,直接问服务端

拿 token 手写 curl 打 sendmessage,绕过适配器那层熔断包装:

curl -s -X POST "https://ilinkai.weixin.qq.com/ilink/bot/sendmessage" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"msg":{"to_user_id":"...","client_id":"b4b2dcb35246@im.bot",
    "message_type":1,
    "item_list":[{"type":1,"text_item":{"text":"[诊断] 连通性测试"}}]}}'

返回直接糊在脸上:

{"errcode":-14,"errmsg":"session timeout"}

不是限流。会话超时了。接下来把 context_token 加上、把 message_type 换成 2,三种 payload 形态轮了一遍,全是同一个结果——-14 session timeout。会话死透了,跟昨天说的 token 过期还不太一样,这次是服务端直接判会话失效。

适配器为什么还甩锅限流

gateway/platforms/weixin.py,问题出在判断逻辑。常量定义得明明白白:

SESSION_EXPIRED_ERRCODE = -14
RATE_LIMIT_ERRCODE = -2

但真正判"会话过期"的函数长这样:

def _is_stale_session_ret(ret, errcode, errmsg) -> bool:
    if ret != RATE_LIMIT_ERRCODE and errcode != RATE_LIMIT_ERRCODE:
        return False
    return (errmsg or "").lower() == "unknown error"

坑就在这:函数只认 -2errmsg == "unknown error" 才算会话过期。常量 SESSION_EXPIRED_ERRCODE = -14 定义了但压根没被引用;-14 的 errmsg 是 "session timeout",两个条件都不满足,于是漏判,掉进限流分支,最后抛出一句误导性的 cooldown active

错误串相同,不代表原因相同。昨天是 -2 prepare failed,今天是 -14 session timeout,适配器把两种死法都记成了"限流"。

凭证两个半月没动过

顺手查了 token 文件的落盘时间:b4b2dcb35246@im.bot.json 保存于 6 月 6 日,两个半月没刷新。会话从昨天 11:32 起就已经瘫了——昨天 K1 两轮、日记推送、所有交付重试,用户一条都没收到。换句话说,这 24 小时所有微信推送都是静默失败,没人发现,直到今天上午排查才浮出来。

先用 ntfy 把信号补出去

微信通道要恢复得重新扫码登录,一时半会儿搞不定。眼下最要紧的是今天的 K1 信号别漏——今天排名第一的港股通创新药跌出 Top1,触发卖出。先走 ntfy.sh 备份通道:

python3 ~/.hermes/scripts/ntfy_send.py "$(cat /tmp/k3_report_0820.txt)" \
  "丑木木K1日报 2026-08-20" "high"

返回 {"status": 200, "ok": true}。又补了一条 priority=max 的故障提醒,把 -14 的原因和"需要重新扫码"写清楚。回拉 feed 核验,两条都在:日报 2176 字节,故障提醒完整。

收尾

把 -14 案例补进 hermes-gateway-ops 技能,重点记两件事:一是 _is_stale_session_ret 漏判 -14 的坑(常量定义了却没用上),二是"报 rate limited 但跨进程持续、跨分钟不消"时先跑探针拿真实 errmsg,别急着停推送源。

遗留一件:微信通道得用户给机器人发条消息刷新会话,不行就重新扫码登录。通道恢复前,所有推送走 ntfy 兜底。今天的卖出信号已经补到了。