企业把订单、工单、合同或报销流程自动化后,最危险的问题不一定是“流程没跑”,而是同一件事跑了两遍:生成两张单、发两次通知、重复扣减库存,或者把同一个文件再次写进系统。表面看是偶发故障,真正缺的是重复输入和重试边界。
自动化流程重复执行并不只发生在复杂系统里。定时轮询、Webhook 重送、连接超时、多个流程副本、并发处理和人工补跑,都可能让同一个业务对象再次进入流程。企业需要保证的不是“每次只触发一次”,而是“即使触发多次,业务结果也只完成一次”。
看到失败,不代表前一步没有成功
自动化调用另一个系统时,可能已经成功创建订单,但返回结果在网络中断时丢失。当前流程只看到超时,于是按重试策略再发一次。如果目标系统无法识别这是同一次业务请求,就可能创建第二条记录。
AWS 在关于安全重试的技术说明中强调:临时故障可以通过重试恢复,但前提是重试不会产生额外副作用。否则一次创建资源的请求被重复执行,就可能得到两个结果。
所以流程日志不能只有“成功”和“失败”。至少还要能表达“已发送但结果未知”“目标已存在”“等待人工复核”和“确认可以重试”。结果不明确时直接重跑,是重复处理最常见的入口之一。
另一个容易忽略的来源,是同一套流程存在多个副本。测试环境没有关闭、旧版本仍在运行,或者两个部门各自建立了相同触发条件,一条新记录就可能同时启动两条流程。此时单看每条流程都没有报错,但业务端已经收到两个结果。因此上线清单里还要记录流程名称、环境、负责人和启用状态。
先识别同一件业务,再谈流程次数
很多流程只有每次运行自己的 Run ID,却没有业务唯一编号。系统知道今天跑了两次,却不知道两次处理的是不是同一张订单。
企业应该为需要避免重复的对象选择稳定标识,例如来源系统订单号、工单号、合同编号或“来源系统 + 记录 ID”。这个标识代表业务意图,不应随着每次重试重新生成。
还要注意,唯一编号本身不能包含密码、身份证号、客户邮箱等敏感信息。需要跨系统传递时,可以使用内部记录 ID 或不可逆摘要,并在本地保留对应关系。
业务唯一编号和每次运行编号要分开。运行编号用于排查这一次执行,业务编号用于判断多次执行是否属于同一件事。如果每次重试都生成新的业务编号,去重机制就会把它当成新订单;如果不同订单误用了同一个编号,系统又可能把真实的新业务挡掉。编号规则必须在来源系统确定,并经过重复与冲突测试。
幂等不是“发现重复就全部跳过”
幂等的大白话解释是:同一个操作执行一次和执行多次,最终业务结果保持一致。Microsoft 在 Power Automate 触发器排障文档中也建议流程考虑重复输入,例如创建 SharePoint 文档前先检查是否已经存在,或者用数据键约束阻止重复记录。
但判断重复不能只看客户名称、日期或文件名。两个客户可能同名,同一客户也可能在一天内下两张订单。企业要把业务唯一编号、关键输入摘要和处理状态一起保存。
如果同一编号再次到达、输入完全一致且第一次已经完成,可以返回原结果;如果同一编号对应的金额、明细或版本发生变化,就不能静默跳过,应进入冲突队列让责任人判断。
写入前检查,写入后再回读
可靠流程通常需要一张处理记录,至少包含:业务唯一编号、来源、首次接收时间、当前状态、目标系统记录号、最后一次尝试、错误原因和复核人。
在创建订单、发送正式通知、生成合同或扣减库存前,先查询该编号是否已经处理;执行后再回读目标系统,把真实记录号写回。只有这样,流程恢复时才知道应该继续、跳过、补偿还是交给人工。
日志记录也不能代替数据库约束。两条并发流程可能在几乎同一时间查询,都看到“尚未处理”,随后各自创建一条记录。对关键对象,除了流程层检查,还应让目标系统通过唯一键、受控的更新方式或事务边界阻止并发重复;做不到时,应把写入动作串行化并设置人工异常队列。
Stripe 的接口文档用 idempotency key 识别同一次创建或更新请求的重试,避免重复创建对象。企业不一定使用同一产品,但“同一业务意图使用同一个键、输入变化不能假装是同一次请求”的原则可以借鉴。
五项上线前检查
- 为订单、工单、合同或报销记录确定一个跨流程稳定的业务唯一编号,并写清生成责任。
- 列出哪些动作有不可忽略的副作用,例如建单、扣库存、发正式邮件、生成文件和写财务记录。
- 增加处理状态与目标记录号,流程超时后先查询实际结果,不凭“失败”字样直接重跑。
- 对同一编号但输入发生变化的情况建立冲突队列,不覆盖旧结果,也不自动跳过。
- 用同一测试记录连续触发两次,确认最终只有一个业务结果,同时日志能看到第二次如何被识别和处理。
核心判断:自动化的可靠性不在于保证永远只触发一次,而在于重复触发、重试和补跑发生时,系统仍不会把同一件业务办两遍。
如需梳理订单、合同、工单或报销流程中的业务编号、重试策略、状态记录和异常处理,可以联系煜企智能,从现有表格与流程运行记录开始评估。


