自动化向客户系统发送创建记录的请求,却在收到响应之前超时。到底是创建失败,还是已经成功,只是确认消息丢了?
如果直接重试,团队可能得到两条记录。类似的不确定性还可能导致邮件重复发送或下游操作重复执行。无论流程里有没有 AI,这都是需要处理的问题。
可靠的自动化不能只有“重试”按钮,还要能应对结果不明确的情况。下面介绍的是示例设计思路,不是已部署系统的效果承诺。
区分失败和结果未知
明确被拒绝的请求,与没有收到响应,是两种情况。输入不合法通常需要修改;临时服务中断可能适合稍后再试;提交业务操作后超时,则可能要先检查目标端是否已经执行。
在流程里保留这种区别。可以设置待处理、执行中、成功、失败和待调查等状态。不要把所有非成功响应,都理解为目标系统没有发生变化。
为业务动作分配稳定编号
任务被接收时创建操作编号,在所有重试中保持不变。它不同于每次执行都会变化的尝试编号。
例如,“为已接收的第 847 号咨询创建 CRM 记录”是一个业务动作。第一次和第二次尝试不应该被当成两个无关指令。避免在会进入日志或第三方系统的编号里放入个人信息。
操作状态要保存在下一位执行者能够读取的位置。只放在某个进程的内存里,重启后就会丢失。
利用目标系统已有的防重复能力
部分 API 支持幂等机制,让重复尝试指向同一个业务动作,而不是再次创建。Stripe 的幂等请求文档提供了一个具体例子:对支持的操作使用同一个幂等键重试。
但不能假设其他服务规则相同。应检查支持的接口、键的有效期、参数限制和响应含义。每次重试都换一个新键,会失去防重复意义;把旧键用于真正的新操作也不正确。
一个目标端的幂等能力,不会自动保护整条多步骤工作流。
协调执行者,而不只检查请求
两个执行者可能同时看到一个待处理任务,都检查“结果还不存在”,然后都执行操作。当步骤可能重叠时,简单的“先查再写”并不充分。
根据系统选用合适的原子认领、唯一性约束,或目标端支持的机制。同时考虑:外部操作已经成功,本地状态还没保存,执行者就崩溃了。这个时间差需要核对与补偿流程来处理。
不能因为某一层过滤了重复事件,就宣称整个流程“恰好执行一次”。
给重试设置边界
对于目标服务明确说明可以重试的错误,设定最大尝试次数、适当递增的间隔和总截止时间,并遵循其限流与重试说明。
超过边界就转入异常队列,提供足够的调查信息,而不是无限重试。记录操作编号、尝试次数、安全的错误详情和已知目标端编号;不要把凭据和不必要的客户资料复制进日志。
消息发送尤其需要谨慎
发送邮件与修改一个字段不一样。如果服务商已接收邮件,只是确认丢失,再次发送可能产生另一封邮件。查询服务商状态或使用其防重复能力可能有帮助,但是否提供、能保证什么,需要分别核实。
当结果无法安全确认时,应交给负责人调查,而不是猜测。运营人员需要分清:自己是在核对一封邮件是否发送,还是批准发送一封新邮件。
专门测试不顺利的时刻
- 同一个事件提交两次。
- 两个执行者同时处理同一操作。
- 目标系统接收请求之后再模拟超时。
- 保存成功状态之前重启执行者。
- 用尽重试次数,检查异常队列。
- 恢复失败批次,但不重放已完成的操作。
验收问题应当很实际:团队能否解释哪些业务操作已经发生,哪些仍然需要人作决定?