Stripe 的支付系统中,一个很常见的问题是:同一个事件可能被重复发送,不同事件也不一定按照产生顺序到达。
这道题算法并不复杂,但很适合考察候选人对幂等、状态更新和边界情况的处理。
You are building a simplified webhook processing system for payment events.
Each event contains:
event_id
payment_id
timestamp
status
Possible statuses are:
CREATED
PROCESSING
SUCCEEDED
FAILED
Implement a function that processes incoming webhook events and maintains the latest status of each payment.
Requirements:
- The same
event_idmay be delivered more than once. It should only be processed once. - Events may arrive out of order.
- For each
payment_id, only the event with the latest timestamp should determine its current status.
Return the final status of every payment after all events have been processed.
Example
Input:
e1,p1,100,CREATED
e2,p1,120,PROCESSING
e2,p1,120,PROCESSING
e3,p1,150,SUCCEEDED
e4,p1,130,FAILED
e5,p2,200,CREATED
e6,p2,240,SUCCEEDED
Output:
p1 -> SUCCEEDED
p2 -> SUCCEEDED
这道题其实只需要维护两类状态。
第一类是已经处理过的 event_id。
可以使用一个 Set:
processedEvents
每次收到事件时,先检查:
if event_id already exists:
ignore
这样就解决了重复投递的问题。
第二类状态是每个 payment 当前最新的事件。
例如:
paymentState[payment_id] = {
timestamp,
status
}
收到新的事件之后,只需要比较 timestamp。
如果当前 payment 还没有任何记录,就直接保存。
如果新事件:
newTimestamp > currentTimestamp
再更新状态。
否则说明这是一个较旧的事件,即使它刚刚才到达,也应该忽略。
整个流程实际上就是:
去重
↓
找到 payment
↓
比较 timestamp
↓
决定是否更新状态
不需要复杂的数据结构。
容易踩坑的地方
最常见的问题是把“到达顺序”当成“事件发生顺序”。
例如:
SUCCEEDED timestamp=150
FAILED timestamp=130
如果代码每收到一个 Webhook 就直接覆盖状态,最终就会错误地得到 FAILED。
另一个容易忽略的问题是重复事件。
支付系统中的 Webhook 通常需要考虑 retry。如果同一个事件被执行两遍,而事件处理过程中还包含退款、发货或者余额修改,就可能产生更严重的问题。
所以这里的 event_id 去重,本质上是在考 Idempotency(幂等性)。
Follow-up
What if two events for the same payment have the same timestamp?
这时候就不能单纯依赖 timestamp。
比较合理的做法是先向面试官确认系统是否提供额外的 sequence number。
例如:
event_id
payment_id
timestamp
sequence
status
然后比较:
(timestamp, sequence)
而不是自己随意假设两个事件的先后关系。
如果系统没有任何额外顺序信息,那么两个完全相同 timestamp 的事件之间可能本身就不存在可靠的先后关系,这一点应该明确说明。
这题真正想看的不是 HashMap 会不会写。
核心是候选人能不能意识到:
重复投递 != 重复执行
到达顺序 != 发生顺序
很多支付系统问题最后都会落到类似的工程细节上。
第一版需求可能只是保存 payment 状态,但一旦加入 retry、乱序或者并发,代码结构是否清晰就会变得非常重要。
如果输入一共有 n 个 Webhook Event,使用 HashSet 和 HashMap 后,平均时间复杂度可以做到:
O(n)
空间复杂度同样是:
O(n)
整体并不难,但非常适合 Stripe 这种偏实际业务场景的 Coding Interview。
csoahelp 面试辅助
Stripe 的面试题很多并不是传统 LeetCode 模板,而是从支付、商户、交易和数据处理场景逐步增加 requirement。
真正困难的地方往往不是代码量,而是现场能否快速判断:
这个条件应该修改现有逻辑,还是增加新的状态?
边界情况应该怎么处理?
面试官继续追问时,现有设计能不能自然扩展?
csoahelp 提供大厂技术面试实时文本辅助以及 Mock Interview 服务,覆盖 Stripe、Google、Meta、Amazon、TikTok、Microsoft 等公司。
面试过程中可以通过实时文本形式辅助理解题意、梳理解题方向、处理 Follow-up,并帮助组织复杂度和思路表达。
对于 Stripe 这类业务场景较强、需求会逐步变化的面试题,提前熟悉这种解题节奏通常比单纯刷大量算法题更有帮助。
我们也有代面试,面试辅助,OA代写等服务助您早日上岸~

