Dispute Timeout
争议不能无限期挂着。这个模块每分钟扫描到期争议,按策略执行
hold/release/refund。
职责
| 负责 | 不负责 |
|---|---|
扫描 slaDueAt 到期的争议 | 受理争议(fulfillment) |
按 dispute.onTimeout 执行动作 | 决定赔付比例(policy-settings) |
| 幂等处理 | 真实资金划转 |
数据来源
复用 fulfillment_disputes,读取:
status(under_review/awaiting_evidence)slaDueAttaskId/deliveryId
执行动作
| 动作 | 行为 |
|---|---|
hold(默认) | 不动作,继续等待人工 |
release | 触发托管放款 |
refund | 触发托管退款 |
执行时:
actor = system:auto-release- 写入状态层,保留因果链
- 同一争议重复扫描不会重复执行(幂等)
调度
由 @nestjs/schedule 驱动,每分钟执行一次。
@Cron(EVERY_MINUTE)
scanDueDisputes()
├─ 查询 status in (under_review, awaiting_evidence)
│ and slaDueAt <= now
├─ 对每条按策略执行
└─ 记录执行结果与托管的关系
Dispute 到期
→ onTimeout
├─ hold → 无动作
├─ release → escrow.release()
└─ refund → escrow.refund()
│
└─ EscrowService 校验状态与金额守恒
└─ 写 L0 痕迹超时动作不能绕过托管状态机:只有 held 状态才能结算。
边界与限制
| 限制 | 说明 |
|---|---|
| 单实例语义 | 多实例部署依赖幂等避免重复执行 |
| 无重试队列 | 失败需下次扫描重试 |
| 无通知 | 不主动通知买卖双方 |
| 动作有限 | 只有三种 |
| 依赖时钟 | 服务器时间偏移会影响判定 |
源码位置
libs/modules/src/dispute-timeout/
└── services/dispute-timeout.service.ts