自动化向客户系统发送创建记录的请求,却在收到响应之前超时。到底是创建失败,还是已经成功,只是确认消息丢了?

如果直接重试,团队可能得到两条记录。类似的不确定性还可能导致邮件重复发送或下游操作重复执行。无论流程里有没有 AI,这都是需要处理的问题。

可靠的自动化不能只有“重试”按钮,还要能应对结果不明确的情况。下面介绍的是示例设计思路,不是已部署系统的效果承诺。

区分失败和结果未知

明确被拒绝的请求,与没有收到响应,是两种情况。输入不合法通常需要修改;临时服务中断可能适合稍后再试;提交业务操作后超时,则可能要先检查目标端是否已经执行。

在流程里保留这种区别。可以设置待处理、执行中、成功、失败和待调查等状态。不要把所有非成功响应,都理解为目标系统没有发生变化。

为业务动作分配稳定编号

任务被接收时创建操作编号,在所有重试中保持不变。它不同于每次执行都会变化的尝试编号。

例如,“为已接收的第 847 号咨询创建 CRM 记录”是一个业务动作。第一次和第二次尝试不应该被当成两个无关指令。避免在会进入日志或第三方系统的编号里放入个人信息。

操作状态要保存在下一位执行者能够读取的位置。只放在某个进程的内存里,重启后就会丢失。

利用目标系统已有的防重复能力

部分 API 支持幂等机制,让重复尝试指向同一个业务动作,而不是再次创建。Stripe 的幂等请求文档提供了一个具体例子:对支持的操作使用同一个幂等键重试。

但不能假设其他服务规则相同。应检查支持的接口、键的有效期、参数限制和响应含义。每次重试都换一个新键,会失去防重复意义;把旧键用于真正的新操作也不正确。

一个目标端的幂等能力,不会自动保护整条多步骤工作流。

协调执行者,而不只检查请求

两个执行者可能同时看到一个待处理任务,都检查“结果还不存在”,然后都执行操作。当步骤可能重叠时,简单的“先查再写”并不充分。

根据系统选用合适的原子认领、唯一性约束,或目标端支持的机制。同时考虑:外部操作已经成功,本地状态还没保存,执行者就崩溃了。这个时间差需要核对与补偿流程来处理。

不能因为某一层过滤了重复事件,就宣称整个流程“恰好执行一次”。

给重试设置边界

对于目标服务明确说明可以重试的错误,设定最大尝试次数、适当递增的间隔和总截止时间,并遵循其限流与重试说明。

超过边界就转入异常队列,提供足够的调查信息,而不是无限重试。记录操作编号、尝试次数、安全的错误详情和已知目标端编号;不要把凭据和不必要的客户资料复制进日志。

消息发送尤其需要谨慎

发送邮件与修改一个字段不一样。如果服务商已接收邮件,只是确认丢失,再次发送可能产生另一封邮件。查询服务商状态或使用其防重复能力可能有帮助,但是否提供、能保证什么,需要分别核实。

当结果无法安全确认时,应交给负责人调查,而不是猜测。运营人员需要分清:自己是在核对一封邮件是否发送,还是批准发送一封新邮件。

专门测试不顺利的时刻

  • 同一个事件提交两次。
  • 两个执行者同时处理同一操作。
  • 目标系统接收请求之后再模拟超时。
  • 保存成功状态之前重启执行者。
  • 用尽重试次数,检查异常队列。
  • 恢复失败批次,但不重放已完成的操作。

验收问题应当很实际:团队能否解释哪些业务操作已经发生,哪些仍然需要人作决定?

扩大自动化之前,也要做好运维交接。如果希望把脆弱的原型完善为可维护流程,可查看原型与交付服务,或发送邮件。