严重级别
高 — 一次操作产生两张有效采购单 + 两套审批流,有重复采购/重复审批风险
环境
- 应用:
xxxxv0.0.1 - 租户:
<租户名脱敏> - 时间:2026-06-11 15:44:55 ~ 15:44:57 (UTC+8)
- 浏览器:Edge 124 / Windows 10
- 页面:
Default/purchaseOrders - 工作流:
workflows.purchaseOrdersApproval
复现步骤
- 进入「3.0采购订单」
- 点击「新增并发起审批」
- 填写表单(低值易耗品,含明细与附件)
- 点击提交(用户反馈仅点击一次)
- 观察列表出现 2 条内容相同的采购单
期望结果
仅创建 1 张采购单、1 条审批实例
实际结果
创建 2 张采购单:
| 主键ID | 采购单号 | 审批实例ID |
|---|---|---|
| 954 | CG260611003 | 12477 |
| 955 | CG260611004 | 12478 |
服务端证据
- gunicorn_access.log:15:44:57 同一 Referer 下 2 条
POST .../WorkflowSvc/doHandle,均 200 - server.log 请求 trace:
3564963c76504851bb7c53307965d852→ create id=95465b81215cb244ac1ae73864fb34d65b7→ create id=955
- 两次请求
argsDict中handleType=0、nodeId=StartNode、rowData.id=None,业务字段完全一致 [QuerySetUpsertDiag] upsert.branch | reason=no_pk | action=create各执行一次
根因判断
- 前端:提交按钮未有效防重复(debounce / loading lock / request dedup)
- 后端:
WorkflowSvc/doHandle对新建发起缺少幂等保护,并发相同 payload 会各建一条
建议修复方向
- 前端(优先):工作流提交期间禁用按钮;同一表单 session 内对
doHandle去重;请求进行中拒绝二次触发 - 后端(兜底):对
handleType=0 + rowData.id=null引入幂等键(如 clientRequestId);短时窗口内相同用户+相同 payload hash 拒绝重复 create;或 DB 层事务锁 - 可观测性:
doHandle入口记录 clientRequestId,便于关联重复请求
影响范围
所有通过「新增并发起审批」/工作流 StartNode 新建业务数据的场景,不仅限于采购订单