如果让你设计一个支持千万级订单超时关闭的延时任务系统,你会怎么做?
我的判断
千万级订单超时关闭用持久化时间桶或延时消息触发,但最终以订单状态和截止时间为准,扫描补偿保证不漏。
创建订单时保存 expire_at,同时发送带订单 ID 和到期时间的延时任务。规模很大时可以按分钟时间桶分片存储,调度器只加载临近窗口;也可使用支持延时的消息系统。不会为每个订单在单机内存创建一个 Timer。
任务触发后用条件更新:
UPDATE orders
SET status = "CLOSED"
WHERE id = ? AND status = "PENDING" AND expire_at <= NOW();
重复触发受影响行数为 0,天然幂等;支付与关闭并发时由状态机和数据库条件决定赢家。关闭成功再发库存释放事件,释放也按订单 ID 幂等。
延时消息可能丢、重复或晚到,所以后台按 expire_at + status 分片扫描超时订单做兜底,对任务触发数、成功关闭数和待支付超时数对账。积压时按到期时间优先恢复并限制数据库并发。
容易答偏踩坑误区
- 单机 DelayQueue 放全部任务。 重启丢失且无法横向扩展。
- 收到任务直接关闭。 必须重新检查状态和真实截止时间。
- 只有延时消息没有扫描兜底。 长期运行后遗漏会积累。