轮换要带健康状态记忆
一、盲目串行的算术
4 key × 3 模型 = 12 组,上游单次约 8 秒 → 全试一遍 96 秒,直接撞上 Vercel maxDuration: 60。表现是:
连续 3 次:60.003s 超时 → 429
比不轮换更糟 —— 用户等 60 秒然后失败。
二、健康状态记忆
进程级内存表:health: Map<"key::model", {until, status}>。
冷却时长按错误性质区分(这是关键,不能一律 30 秒):
| 错误 | 冷却 | 理由 |
|---|---|---|
| 429 配额耗尽 | 10 分钟 | 额度按天重置,几秒内不可能恢复 |
| 503 模型过载 | 60 秒 | 通常几十秒恢复 |
| 403 / 404 | 5 分钟 | 凭据或模型名问题,短期不自愈 |
| 500 / 502 / 504、网络抛错 | 30 秒 | 网关抖动 |
排序:健康组合优先,冷却组合排后而不是删除 —— 健康表是临时的,全部冷却时仍要有兜底可试。
const ordered = [...combos.filter(c => !c.cooling), ...combos.filter(c => c.cooling)];
单次尝试超时 8 秒,防止一个慢组合拖死整轮;最后一组不加超时(反正没有下一组,不如多等一会)。成功即 markSuccess 清除冷却,稳定态下第一组就命中,只需一次上游往返。
三、边界:无状态部署让健康表打折
Vercel 是无状态的,每次请求可能落在不同实例,健康表不共享。所以冷却只是「本实例的经验」,效果是概率性的 —— 实测同样逻辑耗时在 1.7s ~ 31s 之间波动。
结论:健康记忆能显著降低最坏耗时,但不能替代跨实例的共享状态(真要稳定就得放 Redis / KV 之类)。