4.5 KiB
4.5 KiB
DELIVERY_SERVICE_DESIGN
最后更新: 2026-06-14
1. 目标
将“报告生成完成”与“已交付给用户”明确区分,避免把 delivered 误当成只是一条后台状态修改。
2. 设计原则
- 交付是独立业务对象,不等于报告文件存在
- 用户可见状态必须基于真实交付物
- 通知触发点应尽量靠近稳定主链,而不是只挂在单一路由
- 至少一种 MVP 交付方式先闭环
3. MVP 交付方式
当前优先:
- 站内查看 HTML 报告
- 站内下载 PDF
后续可扩展:
- 邮件投递
- 微信/渠道通知
4. 建议对象
delivery_job
delivery_idorder_idchannel(station/email/...)status(pending/ready/sent/failed)payload_jsoncreated_atupdated_at
delivery_attempt
delivery_idattempt_nostatusfailure_reasoncreated_at
5. 当前实现状态
已存在:
delivery_notifications事件表- portal 状态页 / 报告页 / PDF 下载页
delivered但无交付物时不再误报report_readydata.notifications.dispatcher.DeliveryDispatcherscripts/gaokao-delivery-dispatch.pyscripts/gaokao-delivery-watchdog.py(失败返回 exit code2)ready -> sent/缺文件 -> failed/attempt_count递增station通道 dispatch 时会真实生成station_notice,portal 状态页展示“通知已发送”消息卡片email通道使用SMTPDeliverySender发送真实邮件通知,支持GAOKAO_SMTP_*配置,并已通过本地 stub SMTP 验证docs/DELIVERY_RETENTION_OPS_RUNBOOK.mddeploy/systemd/gaokao-delivery-{dispatch,watchdog}.{service,timer}deploy/cron/gaokao-jobs.crontab
未完成:
- 独立
delivery_job/delivery_attempt模型 - 邮件/渠道真实发送执行器
- 告警推送集成(当前只有 watchdog 非 0 退出码)
- 多通道统一投递状态页
6. 当前最短闭环
- 订单进入
delivered - 真实 HTML/PDF 都存在
- portal 显示
report_ready - 状态页提供查看/下载入口
report_ready事件落库且幂等gaokao-delivery-dispatch.py --channel station可把 ready 事件推进到 sent- 缺失交付物时事件转 failed,并记录
failure_reason - 可通过 systemd timer / cron 周期执行 dispatcher,并用 watchdog 暴露失败退出码
7. 下一步实施建议
- 增加失败重试阈值与告警推送
- 增加面向用户的独立通知审计页
- 把事件生命周期细化为
ready/validated/delivered/failed - 区分
station(本地渲染)与email(真实下游推送)两类 channel 的delivered判定 - 再决定是否扩到更多通道
8. 事件生命周期(2026-06-14 修订)
P2-3 整改后, dispatcher 强制走如下状态机:
ready ── 初始化, 还没校验
│
▼
validated ── payload 解析通过 + 交付物 (html / pdf) 校验通过
│ 注意: station channel 在这一步会落 payload, 但不再升级为 delivered
│
▼
delivered ── 真实下游推送完成 (仅 email)
│
▼
failed ── 任意环节失败
ready -> validated必须有 artifact (html / pdf) 真实存在于磁盘validated -> delivered必须由真实 sender 回调成功 (email.send_report_ready返回成功)station通道因为没有真实下游, 永远停在validatedsent字段是 legacy alias, 仍然存在但不应再被新代码依赖
9. 生产化接入口径
仓库内已提供最小 runbook 与调度样例:
- runbook:
docs/DELIVERY_RETENTION_OPS_RUNBOOK.md - systemd:
deploy/systemd/gaokao-delivery-dispatch.{service,timer}/deploy/systemd/gaokao-delivery-watchdog.{service,timer} - cron:
deploy/cron/gaokao-jobs.crontab
注意:当前 watchdog 仍是“带失败退出码的 dispatch 巡检”,并不等于独立通知告警系统。
10. 不可降级的不变量
- 事件状态机
ready/validated/delivered/failed必须被 dispatcher 严格遵守 delivered永远只能由真实 sender 成功返回failed事件必须有failure_reason字段- 同一
(order_id, event_type)必须幂等, 重复 dispatcher 不会产生额外副作用 delivered之后, payload 写入的delivered_at必须等于last_attempt_at
11. 后续工作
- 把独立
delivery_job/delivery_attempt模型实现为 SQLite 表 - 引入
attempt_count与last_attempt_at之外的成功重试预算 - 多通道统一投递状态页 (类似 notification audit 页面)
- 告警推送 (Sentry / 飞书 / 钉钉) 与 watchdog 整合