题目重点:设计餐食下单与配送链路,拆分订单确认、支付、配餐、派单与追踪的可靠性。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练有customer/restaurant/courier三类角色,配送订单;pickup和自取可作为不同履约方式。具体库存、支付与配送时限由题面给定。
- 订单、支付、商家履约与配送独立状态但需一致业务结果;不把一个“成功”布尔值覆盖所有阶段。
解题路线
- customer请求带orderRequestId,服务器校验菜品/价格版本与商家可接单状态,创建order及outbox。支付授权和商家接单按业务选择顺序,失败补偿退款/取消,不承诺跨外部服务原子事务。
- 状态分别记order CREATED/CONFIRMED/CANCELLED,payment AUTHORIZED/CAPTURED/REFUNDED,fulfillment PREPARING/READY,delivery ASSIGNED/PICKED_UP/DELIVERED。每事件含revision和发生证据,旧回调不能倒退终态。
- 派单按地点/容量/路线与接受租约筛候选,双骑手抢同job用CAS;骑手位置流用于ETA,定位更新乱序按device/session sequence处理,不等于证明送达。
- 客户追踪读聚合view,展示支付/商家/配送真实阶段;每服务SPOF分析多副本、持久队列与故障恢复。超时任务持久deadline可扫恢复,不能只有内存timer。
- 异常处理单列商家拒单/缺菜/支付timeout/骑手离线/取消时点,补偿幂等并留审计;对暂时不可用明确“待确认”,而非盲目重试多下单。
手动走一遍
支付已授权后商家拒单,需撤销授权/退款并终止派单;支付回调ACK丢失时先查询paymentId,不重复收费。两个骑手accept同deliveryVersion只有一个成功。
规模与取舍
读菜单/位置/追踪QPS可远高于订单写QPS;位置每骑手每几秒更新需另算。订单核心事务按order分片,商家热门库存写与单城派单热点不能仅靠缓存解决。
易错点与追问
容易失分的边界
- 直接将支付成功等同订单被商家确认,会造成已付款无履约的错误体验。
- 只说每service两个副本不能应对数据库/队列/支付依赖单点,需具体failover和数据恢复。
继续深挖
- 取消晚于开始配餐或取餐时如何定补偿?由明确业务合同,状态机只实现已定规则。
- 跨服务事件漏掉如何对账?基于order/payment/delivery权威记录修复聚合,不以临时pubsub当唯一事实。
