feat(sms): 短信验证码 极光→创蓝 容灾 fallback #204
Reference in New Issue
Block a user
Delete Branch "feat/sms-jiguang-chuanglan-fallback"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
短信验证码已是可切换 provider 架构(极光 / 创蓝)。极光(默认)一旦供应商侧故障(欠费 / 网络 / 服务异常),/sms/send 直接 503 → 用户收不到码、登录中断。本 PR 把极光设为主、创蓝设为备,在极光供应商不可用时自动转创蓝补发,并让后台可区分每次实际走的渠道。
方案(4 个关键决策)
| 决策 | 结论
-- | -- | --
A | fallback 触发范围 | 仅主返回「供应商不可用」(SmsError.status_code == 503:网络 / 余额 / 服务故障)才转备。本地冷却 & 超频(429)、手机号无效(400)不转——不绕过防刷、不为无效号白烧
B | 校验路由 | try-both:极光转创蓝后码在创蓝内存,校验遍历「启用的 fallback 链」(主→备),任一命中即通过;关闭 fallback 时链中只有极光、创蓝零参与
C | 后台可见性 | 成功侧 EVENT_SMS_SEND.details 记 provider / fallback + 分派层日志,风控后台可按号/设备查本次走哪家、是否 fallback
D | 默认开关 | SMS_FALLBACK_PROVIDER 默认空=关(保持现状零风险),生产设 chuanglan 开启,置空即秒回退。仅 Mode B(jiguang/chuanglan)互为主备
🤖 review-pr 深审结论
🟢 可合并 · 置信度 0.9 —— 短信容灾 fallback 设计严谨、实现正确、测试充分(33 用例全过)。
改动:极光(主)→创蓝(备)供应商容灾。分派层
sms/__init__.py重构 +SendResult+config+auth适配 + 完整设计/计划文档。正确性核对(合并后,4 决策落地)
send_code仅e.status_code == 503(供应商不可用)转备;429(冷却/超频)、400(无效号)走raise不转 —— 不绕过防刷、不为无效号白烧。verify_code遍历「主→备」链任一命中即通过;码只在实际发码那家,另一家rec is None→False,不误判、不累加其防爆破计数。auth.py成功事件details记provider+fallback。SMS_FALLBACK_PROVIDER默认空 →_fallback()None → 现状零风险;Literal限定jiguang/chuanglan(Mode B),杜绝误配aliyun(Mode A 自校验)做备。send_code返回int→SendResult,auth.py取cooldown_sec正确;_primary()未知回退 jiguang 防误配。构建/测试(实跑 .venv / py3.12 合并后)
test_sms_base+test_sms_fallback+test_sms_dispatch+test_auth= 33 passed(含 fallback 专项)风险 🟢。设计/计划文档齐备(
docs/superpowers/)。— 🤖 review-pr 自动深审 @guke