[JitWeb] + [Workflow] 工作流新建提交重复请求导致并发 duplicate 创建业务单据(共性问题)

严重级别

— 一次操作产生两张有效采购单 + 两套审批流,有重复采购/重复审批风险

环境

  • 应用:xxxx v0.0.1
  • 租户:<租户名脱敏>
  • 时间:2026-06-11 15:44:55 ~ 15:44:57 (UTC+8)
  • 浏览器:Edge 124 / Windows 10
  • 页面:Default/purchaseOrders
  • 工作流:workflows.purchaseOrdersApproval

复现步骤

  1. 进入「3.0采购订单」
  2. 点击「新增并发起审批」
  3. 填写表单(低值易耗品,含明细与附件)
  4. 点击提交(用户反馈仅点击一次)
  5. 观察列表出现 2 条内容相同的采购单

期望结果

仅创建 1 张采购单、1 条审批实例

实际结果

创建 2 张采购单:

主键ID 采购单号 审批实例ID
954 CG260611003 12477
955 CG260611004 12478

服务端证据

  1. gunicorn_access.log:15:44:57 同一 Referer 下 2 条 POST .../WorkflowSvc/doHandle,均 200
  2. server.log 请求 trace:
    • 3564963c76504851bb7c53307965d852 → create id=954
    • 65b81215cb244ac1ae73864fb34d65b7 → create id=955
  3. 两次请求 argsDicthandleType=0nodeId=StartNoderowData.id=None,业务字段完全一致
  4. [QuerySetUpsertDiag] upsert.branch | reason=no_pk | action=create 各执行一次

根因判断

  • 前端:提交按钮未有效防重复(debounce / loading lock / request dedup)
  • 后端WorkflowSvc/doHandle 对新建发起缺少幂等保护,并发相同 payload 会各建一条

建议修复方向

  1. 前端(优先):工作流提交期间禁用按钮;同一表单 session 内对 doHandle 去重;请求进行中拒绝二次触发
  2. 后端(兜底):对 handleType=0 + rowData.id=null 引入幂等键(如 clientRequestId);短时窗口内相同用户+相同 payload hash 拒绝重复 create;或 DB 层事务锁
  3. 可观测性doHandle 入口记录 clientRequestId,便于关联重复请求

影响范围

所有通过「新增并发起审批」/工作流 StartNode 新建业务数据的场景,不仅限于采购订单