接口超时后的时序图,要先画出“调用方不知道结果”,再画重试。超时只说明响应没有在约定时间内到达,不证明服务端没有执行。若把“超时→重新创建任务”直接连起来,图可能很顺,系统却会重复处理同一请求。
以下用异步导出任务说明提交重试、状态查询和完成回调的区别。代码可放进支持Mermaid时序图的编辑器渲染,再通过 Boardmix 的 Mermaid 图表画布把图、接口约定与评审问题放在一起。画图用于讨论设计;业务接口的幂等、权限和异常行为,仍需实现与测试。

把“请求超时”和“任务失败”画成不同状态
调用方向导出服务提交一项任务,服务端可能尚未收到请求,也可能已经建立任务,只是响应在路上丢失或迟到。两种情况在调用方看来都可能表现为超时,但下一步处理不能依靠猜测。
在本例中,调用方为同一业务请求保留requestId=R-17。服务端根据双方约定的幂等规则识别它,并返回对应的taskId。同一请求重试时沿用R-17;只有确认是新的业务请求,才使用新的请求标识。不能每次网络重试都换一个ID,否则服务端无法把它们识别为同一件事。
| 调用方已知情况 | 图上该表达什么 | 不能直接推断什么 |
|---|---|---|
| 提交超时,没有taskId | 提交结果未知;按接口支持的幂等重试或查询机制核对。 | 任务不存在、服务端没有执行。 |
| 已取得taskId,状态为处理中 | 查询已有任务,等待终态并控制查询频率。 | 需要再创建一个导出任务。 |
| 收到明确的失败终态 | 记录业务失败原因,按业务规则决定是否发起新请求。 | 对所有失败都可以原样重试。 |
| 重试预算用完,结果仍未知 | 停止本轮自动重试,保存标识进入待核对。 | 任务已经失败,可以删除记录。 |
在画图前,确认接口确实支持怎样的幂等机制:标识在哪个范围内唯一、同一标识的参数必须怎样匹配、保留多久、并发请求怎样处理。只有写了requestId字段,并不自动获得幂等保障。带副作用的调用需要这种约定,AWS关于超时、重试与退避的说明也强调了超时后副作用可能已经发生的风险。

先画提交已执行、响应未到达这一条路径
下面的代码专门展开容易误判的情况:导出服务已经建立T-92,但调用方没收到响应。为便于读图,本例约定最多追加两次提交重试;这个次数不是生产环境推荐值,真实上限、总时间预算、退避与抖动应结合接口约定和系统负载确定。
sequenceDiagram
participant C as 调用方
participant S as 导出服务
C->>S: 创建导出,requestId=R-17
S->>S: 建立幂等记录与任务T-92
Note over C,S: 提交响应未按时到达,调用方不知道任务是否已建立
loop 未取得taskId且最多再试2次
C->>C: 按约定退避等待
C->>S: 用同一requestId重试提交
S->>S: 查找既有任务,不重复创建
alt 收到有效响应
S-->>C: 返回taskId=T-92
else 本次仍超时
Note over C: 结果仍未知,保留requestId
end
end
alt 已取得taskId
C->>S: 查询任务T-92的状态
S-->>C: 返回当前任务状态
alt 已成功
C->>C: 记录结果并结束本轮
else 已失败
C->>C: 记录业务失败原因
else 尚在处理
C->>C: 进入有时限的状态跟踪
end
else 仍未取得taskId
C->>C: 转待核对,按requestId追查
end
loop标签同时写退出条件和次数边界:一旦拿到taskId,就不再提交创建请求。后续查询T-92是另一种动作,不占用“创建重试”来反复生成任务。若仍无法确认,图的终点是待核对,不是一个假的“失败”节点。
这个图表达的是交互约定,不会自动执行循环。实际代码还要落实超时范围、重试计数和总时限,并防止应用、网关和SDK各自叠加重试。接口明确拒绝的参数错误,也不能因为画了一个循环,就被当作暂时故障无限重发。
回调单独画,避免把一次成功通知处理两遍
异步任务的终态可能由查询得知,也可能通过回调送达。这两条路径不是先后必然发生:查询已经确认完成后,回调仍可能到达;回调也可能因为确认响应没有送达而重复发送。因此,回调图要交代事件标识、任务归属和状态更新规则。
sequenceDiagram
participant S as 导出服务
participant C as 调用方回调入口
S-)C: 任务T-92终态事件,eventId=EV-9
C->>C: 校验来源、任务归属与事件标识
alt 合法的新事件且状态可更新
C->>C: 去重记录与状态更新一致提交
C-->>S: 确认已接收
else 合法重复事件或终态已按相同结果处理
C-->>S: 按约定确认,不重复通知用户
else 来源无效或状态冲突
C->>C: 拒绝或进入异常核对
C-->>S: 按接口约定返回结果
end
如果EV-9已经处理过,重复到达时不应再次生成用户通知、再次写入一份导出结果。还有一种合法情况:查询先把T-92置为成功,之后首次收到同样成功结果的EV-9。此时事件虽是新的,任务的完成动作却已处理;记录事件并按约定确认,不重复通知,也不把它误判为状态冲突。只有回调结果与已确认终态不相容时,才进入冲突核对。两个入口使用一致的状态规则,具体去重与状态更新如何一致完成,需要研发在实现层明确。
来源校验失败和合法重复不是一回事。前者不能被当作可信任务结果,后者通常要按约定确认已接收,以免对方继续重投。图中保留这两个分支,接口文档再说明签名、事件保留时间、应答码和异常处理。
Mermaid能渲染之后,还要检查这些语义错误
- 把超时画成服务端返回的“超时消息”。调用方本地计时到期与服务端明确返回错误不是同一事件。本例用跨参与者注释说明响应未到达,避免伪造一条实际不存在的回复。
- 重试循环没有停止条件。除了次数,还应说明取得结果后退出,以及总时间预算耗尽后去哪里。不要只有一个“重试”箭头永远回到创建节点。
- 取得taskId后仍重试创建。改为查询已有任务;查询也需要频率和终止约定,但不能悄悄变成新任务。
- 回调与查询各自认定一次完成。共同核对任务状态及事件标识,防止重复副作用和终态回退。
- 每个
alt或loop没有对应的end。先按缩进配对,再检查消息语法;复杂图可以拆成提交、查询与回调几个局部图,保留相同参与者命名。
箭头、循环和分支的语法可对照Mermaid官方时序图文档。语法通过只代表图能生成,不证明幂等逻辑或系统行为正确。若需要先理解参与者、生命线和消息,可阅读UML时序图基础画法。
把图放进评审画布,逐条追问终点
在Boardmix画布中,左侧放提交与重试图,右侧放回调图,底部写接口约定卡:requestId范围、参数一致性、幂等记录期限、重试预算、查询终止条件和异常负责人。讨论结论写回这些卡片及正式接口文档,避免只是给箭头换颜色。
让研发和测试沿四条路径走读:首次响应正常、任务已建但响应丢失、预算用尽仍未知、终态回调重复。每条都问“会不会重复创建或通知、当前知道什么、下一步由谁核对”。若图的最后一格只写“处理异常”,就继续拆到具体记录、动作与责任。
一张可靠的超时重试时序图,应把不确定性放在正确的位置:响应没到时保留未知,拿到任务编号后跟踪原任务,重复事件不重复产生结果,自动处理终止后仍能追查。它给实现和测试提供清楚边界,而不是用一条回环箭头承诺系统总会成功。

