业务场景与批量设计
后台任务的实现从业务规则开始:什么事实触发动作,动作最晚什么时候完成,重复执行会产生什么后果,以及谁负责判断最终结果。相同的队列和重试机制,在会员到期、视频转码和库存提醒中需要不同的业务约束。
下面各篇采用明确的示例规则分析实现,不代表所有产品都采用相同政策。扫描间隔、批次大小、并发数和发送速率都是容量设计样例,需要结合自己的时效和下游限制确定。
从需求到实现需要确定什么
每个场景都需要落实下面的决策,代码里的表、接口和任务应能对应到这些业务约束。
| 决策 | 需要给出的具体答案 | 开发落点 |
|---|---|---|
| 业务目标 | 服务谁,什么结果才算完成 | 业务状态和用户可见结果 |
| 时间语义 | 什么时候生效,最晚什么时候完成 | 期限、数据窗口、任务截止时间 |
| 触发入口 | 请求、事件、扫描分别承担什么 | API、事件接收器、调度计划 |
| 事实来源 | 业务表、外部渠道、指标系统谁说了算 | 查询与核对接口 |
| 数据身份 | 同一业务动作如何识别 | 主键、业务键、周期与版本 |
| 并发约束 | 两个请求或 Worker 同时处理怎么办 | 条件更新、唯一约束、事务边界 |
| 批量与容量 | 按什么单位拆分,瓶颈在哪里 | 分页、检查点、资源池和限速 |
| 通知语义 | 提醒谁,是否合并,什么情况下停止 | 通知意图、渠道记录、过期判断 |
| 故障恢复 | 哪一步可重试,哪里需要查询或人工处理 | 租约、重试、死信、对账 |
| 验收依据 | 如何证明正常与异常路径满足需求 | 业务结果断言、日志和指标 |
各篇中的数据结构是设计所需的最小字段集合,SQL 展示关键约束,伪代码描述事务与处理顺序。它们尚未组成可运行的业务项目,也没有连接真实数据库或外部渠道执行。
共用执行与通知约定
业务处理器可以复用数据库任务队列的领取、租约和尝试模型,但每次执行仍要读取业务当前状态。任务 ID 表示执行记录,业务键表示同一个业务动作,不能相互替代。
通知也需要两层记录:
| 记录 | 最小字段与约束 |
|---|---|
| 通知意图 | intent_id、业务对象、业务版本、提醒阶段、内容模板版本;逻辑键唯一 |
| 渠道投递 | intent_id、渠道、目标标识、状态、尝试次数、渠道请求 ID;按目标去重 |
通知状态可以区分 pending、submitted、delivered、failed 和 suppressed;是否有 delivered 取决于渠道是否提供可信回执。每次重试检查通知是否仍有价值、用户是否仍允许该渠道,并沿用原始业务幂等键。
所有业务 API 都需要校验调用者和对象所属范围。示例中的内部重放、重跑、规则修改接口需要相应操作权限与审计记录,不因它们是后台接口就跳过鉴权。
从案例中提取可以复用的判断
各篇先用一个具体需求比较候选方案,用时序图展示参与者、调用与关键分支,再用同一业务对象的记录变化解释正常与故障路径。时间、ID 和数量都是推演样例,不是实际运行日志。
时序图从上往下表示先后,横向生命线表示参与者;实线箭头表示请求或处理动作,虚线箭头表示响应。alt 表示互斥分支,opt 表示可选路径,loop 表示重复处理,par 表示可能交错的并发路径。一个图中合并展示的 Worker,在实现中可以拆为领取、业务处理与通知发送等独立组件。
迁移到自己的项目时,先保留业务必须成立的约束,再调整组件和容量。下面这些约束相似,但实现对象不同:
| 场景 | 优先守住的约束 | 因此需要的机制 |
|---|---|---|
| 会员 | 不因后台整理延迟而多授权 | 访问时核对期限,后台整理与通知分开 |
| 订单 | 同一订单不能同时有效支付和关闭 | 条件状态转换,渠道结果另行核对 |
| 预约 | 名额不超卖,改期失败不丢原预约 | 占位事务、请求幂等和预约版本 |
| 报表 | 用户不能看到半份或混合版本结果 | 固定输入身份、分片去重、完整后发布 |
| 对账 | 未取得完整事实不能启动错误补偿 | 采集检查点、完整性标记和证据复核 |
| 库存 | 高频变化不能产生无限告警或采购 | 当前状态、告警轮次、采购身份 |
| 监控 | 需要区分故障、通知和人工响应 | 规则状态、通知阶段和确认记录 |
| 文件 | 旧处理不能覆盖新文件的正式产物 | 源版本、处理版本和条件发布 |
| 物流 | 迟到消息不能随意覆盖当前事实 | 原始事件、归并规则和状态版本 |
| 清理 | 已失效不等于已删除,旧候选不能误删新对象 | 请求校验、执行前复核和对象版本 |
增加一个字段时,应能说明它参与哪个判断。例如 version 应指出是哪种变化递增、哪个旧操作因此退出;只加字段而不在更新条件里使用,不会自动获得并发保护。
同样,选择队列之前先定位故障窗口:业务已经提交、动作却没保存,还是动作已完成、确认却丢失。前者需要可靠保存待办意图,后者需要识别重复结果;两者都叫“失败”,恢复方式却不同。
场景入口
| 场景 | 应该由什么触发 | 批量处理时的关键点 |
|---|---|---|
| 电商订单 | 创建延迟检查任务,到期时重新判断 | 逐订单条件更新,支付与关闭竞争 |
| 会员订阅 | 请求校验、到期扫描或延迟任务、续费事件配合 | 分离权益、状态更新与限速通知 |
| 预约提醒 | 预约确认、改期和开始前的提醒时间 | 按预约版本和参与人拆分,错过时效后跳过 |
| 报表统计 | 固定周期和明确的数据窗口 | 按租户或分区计算,完整后发布 |
| 支付对账 | 账单可用或周期拉取 | 分页落原始流水,再匹配和处理差异 |
| 库存补货提醒 | 库存变化与兜底扫描 | 同一 SKU 的变化聚合,按告警轮次去重 |
| 系统监控 | 指标采集、规则评估和状态变化 | 根因分组与抑制,避免千条告警同时通知 |
| 文件异步处理 | 文件完成上传并通过校验 | 按资源成本限并发,部分失败独立重试 |
| 物流通知 | 承运商回调与状态补查 | 原始事件去重、状态归并、通知分发 |
| 数据维护 | 保存到期时间并周期清理 | 过期即拒绝使用,物理回收分批进行 |
国内公开资料与本文设计的对应关系
以下资料核对于 2026 年 10 月 29 日。团队技术文章、产品规则和开放接口文档提供的证据不同:团队文章说明特定时期的建设经验,产品文档说明外部行为或接入约束,社区文章还要辨认作者与原始出处。各篇区分来源明确描述的内容与本文据此提出的实现建议;本文的 SQL、时序图及 1000 个对象的推演仍是教学示例。
| 场景 | 国内资料及性质 | 结合正文关注什么 |
|---|---|---|
| 订单超时 | 阿里云 RocketMQ 官方接入说明 | 定时消息不能撤回,付款后如何处理旧检查 |
| 会员订阅 | 阿里云 ECS、RocketMQ 真实产品规则 | 提醒阶段、权益结束与数据保留分别定义 |
| 预约提醒 | 腾讯会议官方集成方案 | API 与回调汇入统一通知入口,区分单次与系列预约 |
| 报表统计 | 阿里云开发者社区方案、SchedulerX 官方文档 | 重复子任务与失败后汇总,不能直接发布半份结果 |
| 支付对账 | 美团技术团队历史建设实践 | 明细与总数核对、差异复核及自动或人工处置 |
| 库存管理 | 淘宝开放平台事件协议 | 仓库与 SKU 维度、外部事件身份、订阅权限 |
| 系统监控 | 腾讯云可观测平台官方产品方案 | 收敛字段、首次等待与通知频率的时效代价 |
| 文件处理 | 腾讯云点播、媒体处理官方接入说明 | 区分任务积压和回调缺失,按任务 ID 补查 |
| 物流通知 | 快递100API 在腾讯云社区的历史接入经验 | 订阅状态与运输状态分开,确认接收与重推分开 |
| 数据维护 | 阿里云 OSS 官方产品说明 | 周期回收与即时失效分工,注意配置覆盖语义 |
原文链接和具体分析放在各篇对应章节与参考资料中。没有公开完整生产实现的场景,保留这一证据边界,不将产品功能介绍改写为某团队的生产复盘。
同一场景还可以比较不同厂商解决问题的位置。例如报表同时涉及 SchedulerX 的分片与重刷、FlowX 的业务日期依赖与配额;文件处理则结合腾讯云的结果补查、火山引擎的元信息就绪问题,以及美团流水线的领取确认与恢复设计。各篇在上述章节之后继续展开这些资料。
| 厂商或团队 | 本专题补充分析的位置 | 值得对照的工程问题 |
|---|---|---|
| 阿里 | 库存、报表、物流、可观测性 | TCC 迟到预留、历史数据重刷、事件流死信、失败分片追踪 |
| 腾讯 | 会员、订单、预约 | 扫描与渠道回调解耦、延迟消息空洞、回调确认与重试 |
| 火山引擎 | 报表、文件、监控、清理 | FlowX 的依赖与资源门槛、元信息尚未就绪、事件轮次、对象版本清理 |
| 美团 | 对账、文件、监控、物流、清理 | 明细与汇总解耦、Worker 领取竞争、事件证据、分区同步、巡检治理闭环 |
跨场景借鉴时需保留原场景的条件:CI/CD 作业的领取协议可以启发转码恢复设计,但不证明外部转码服务能被相同方式取消;结算平台接受中间汇总延迟,也不代表最终付款允许使用不完整数据。
请求检查、事件和时间任务怎样配合
| 入口 | 负责什么 | 单独使用会漏掉什么 |
|---|---|---|
| 用户请求 | 当次访问的权限和最新页面状态 | 不登录、不访问的人 |
| 业务事件 | 及时接续付款、上传、发货等变化 | 仅因时间流逝而到期的对象 |
| 到期任务或扫描 | 提醒、过期转换、历史修复 | 不能代替访问时的授权判断 |
| 对账或兜底扫描 | 发现缺事件、缺任务、状态差异 | 可能晚于实时路径,必须有时效约束 |
业务读取时就能根据期限判断的结果,不必等待批处理改完状态才生效。物理清理与用户通知则可以按各自的时效异步推进。
批量的四种粒度
“1000 个用户同一天到期”不等于建立一个包含 1000 人的巨型任务。通常需要区分:
- 发现批次:扫描器一页读取多少候选,例如 100 条。
- 业务动作:每个会员周期、订单或文件独立判断和保存结果。
- 执行并发:Worker 同时处理多少动作,受数据库与下游容量限制。
- 通知分发:每人、每渠道保存发送结果,并按供应商配额限速。
一次读取 100 条,不代表同时发起 100 个外部请求。一个人处理失败,也不应导致已经成功的其他 99 人重新接收通知。
通知结果需要单独记录
| 阶段 | 能证明什么 |
|---|---|
| 生成通知意图 | 业务决定需要提醒,内容与对象可追踪 |
| 渠道接受请求 | 邮件、短信或推送服务接受提交 |
| 回执报告送达 | 渠道提供了它定义的送达结果 |
| 用户已读或已操作 | 产品获得明确的用户行为 |
对推送服务的成功响应,不能直接记作“用户已经看到”。通知失败不应让已经完成的订单关闭或会员状态变更回滚。
邮件服务的实际容量也有不同维度。例如 SES 同时限制滚动 24 小时发送量和每秒接收速率,见发送配额说明。批处理需要同时核对这些限制。
参考资料
- Amazon SES:Managing sending limits