SWE / FinHub · Onsite Coding / Event Processing

Coinbase Kafka 订单:New、部分成交、完成与取消条件

题目提供 NEW/FILLED 样例与 getOrderStatus,追问无成交才可 CANCEL;区分事件幂等与订单状态机。

题目重点:题目提供 NEW/FILLED 样例与 getOrderStatus,追问无成交才可 CANCEL;区分事件幂等与订单状态机。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练版单 orderId 的事件按分区顺序输入,NEW 给 totalQty>0,FILLED 给本次成交量>0;同一订单的 symbol/side 不能中途改变。
  • 原始样例未给 event ID;如果上游可能重放,必须增加 eventId 或 Kafka offset+partition 等稳定标识才能可靠区分重试与两笔相同数量的真实 fill。
  • 无 fill 可 CANCEL;取消后后续 fill 拒绝或隔离,题目未明确异步竞态处理。getOrderStatus 对未知 ID 的返回以接口契约为准,训练版 null。

解题路线

  1. 状态 orderId→(totalQty,filledQty,state,attrs)。NEW 若首次出现则创建;FILLED 先要求订单存在、未取消/完成且 0<qty≤totalQty−filledQty,再累计,filled=0 为 NEW、0<filled<total 为 IN_PROGRESS、filled=total 为 COMPLETED。
  2. CANCEL 仅在 filledQty=0 的订单允许,转为 CANCELED;已部分成交不可按题目扩展直接取消。若产品语义实际允许撤销剩余量,要另定义不同题。
  3. 消费消息与更新 DB 的提交需与 Kafka offset 协调;至少一次消费下先按 eventId 去重再改状态,状态与去重记录同事务写入,然后提交 offset。没有 eventId 时只能指出无法完美去重。
  4. 保留失败事件或错误原因:FILLED 超量、重复 NEW 属性冲突、无订单 FILLED、取消后 FILLED。读 API 只读已提交订单视图。
  5. 用样例 1234 的 5+3+2 和 1111 的 5/10 核验;再测两条数量相同但 event ID 不同的合法 fills,避免按数量去重。

手动走一遍

1234 NEW 10→NEW;FILLED 5→IN_PROGRESS(5/10);FILLED 3→IN_PROGRESS(8/10);FILLED 2→COMPLETED(10/10)。5678 NEW 20 后 CANCEL→CANCELED;1234 成交过后 CANCEL 不允许。

规模与取舍

E 条有序事件每条平均 O(1) 哈希更新,O(O+E_id) 存储,其中 O 为订单数、E_id 为保留的去重 ID 数;若去重记录设置有限保留期,必须与最大重放期协调。Kafka/数据库持久性和顺序开销另算。

易错点与追问

容易失分的边界

  • 把每条 FILLED 数量当累计量而不是本次增量。
  • 按 (orderId,qty) 去重,两笔相同成交量会被误删。
  • 先提交 Kafka offset 后写状态,崩溃时丢事件。
  • 部分成交后仍允许原扩展中的 CANCEL。
  • 把此题与 live/paused 命令状态机混为一题。

继续深挖

  • Kafka 重放但无 eventId 时能否保证正确?
  • 同 orderId 消息跨 partition 乱序怎么办?
  • 若允许撤销未成交剩余量,状态和数量怎样定义?
  • 如何处理 FILLED 与 CANCEL 竞态?
✓已复制微信号!