#322 幂等键在失败重试路径换 token:error 终态咽喉清 next_step × retry_wakeup 铸新 token,外部去重失效(实弹复现)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- python
- Domain
- backend, distributed-systems
Research direction
Start with plaita/server/flow_worker.py at _persist_state_or_raise and the retry wakeup path around lines 4270–4287; read the ownership and worker protocol references in core/ownership.py and docs/WORKER_PROTOCOL.md §2.1. Trace how terminal error persistence clears next_step and how retry assigns a step ID, then add the proposed regression coverage for a failed side effect followed by retry. Done means the retry reuses the original connector idempotency key; the issue leaves the design choice for preserving it to the owner.
Written by the indexing model from the issue text.
Description
优先级 P1
depends-on: #322
缺陷:失败重试路径连接器幂等键漂移——「同逻辑步骤重试 N 次 = 至多 1 次副作用」核心承诺在 G1/人工 retry 主路径失效
结论
#322 的幂等键稳定性锚是「重投读同一行 ⇒ 同 token」(core/ownership.py 模块 docstring、docs/WORKER_PROTOCOL.md §2.1:「同逻辑步骤重试 N 次 = 至多 1 次副作用」)。但 error 终态化会清掉行上的 token,retry 唤醒必然重铸新 token——两次执行携带不同 Idempotency-Key,外部系统按新请求处理,重复副作用照常发生。失效点恰是重复风险最高的时刻:上一次尝试已以外发了收据(如 POST 成功后响应解析失败)。
链路(当前 main 5637548c,全部实读)
- step k-1 落盘声明
next_step={node_id: X, step_id: T1}(plaita/server/flow_worker.py_next_step_from_context,step_persist 铸点)。 - worker 循环顶部消费
_bind_step_ownership(flow_worker.py:4960 附近)绑定 T1 → 节点 X 的 HTTP POST 携带Idempotency-Key: {root}:T1:X。 - X 在副作用已发生后失败(如 POST 成功、响应处理抛错)→
state.status = "error"→ 经_persist_state_or_raise落盘。 - 终态咽喉无条件清 token(flow_worker.py:2371-2374,#320 不变量 1 机械化点):
if getattr(state, "status", None) in TERMINAL_EXECUTION_STATUSES: state.pending = None state.dispatch_pending = None state.next_step = None # ← T1 在此丢失,"error" ∈ TERMINAL_EXECUTION_STATUSES - retry 载体 → retry_wakeup 铸新 token(flow_worker.py:4270-4287):
if not declared_step_id(state.next_step)恒真(已被 4 清空)→new_step_id()铸 T2 → 重跑 X 携Idempotency-Key: {root}:T2:X。 - k1 ≠ k2:外部去重完全失效。
注:进程内 redelivery 重试(未终态化,行上 T1 原样)同键保证成立;破坏面精确限定在「终态失败 → retry 唤醒」——G1 预算耗尽终态化后的人工/自动 retry、deterministic_failure_exhausted 后的 retry 都走此路。
实弹探针(真组件复现,非推演)
用真 FlowExecution(OwnershipMixin)+ 真 declared_step_id/new_step_id/connector_idempotency_key + 真 TERMINAL_EXECUTION_STATUSES,按上述 4/5 的逐字逻辑驱动:
[首跑] 绑定 token=db2d7693… 连接器键=d323f155…:db2d7693…:call-api
[终态化] error ∈ TERMINAL? True → next_step = None
[retry唤醒] 重新铸造 token=f003318e…
[重试跑] 绑定 token=f003318e… 连接器键=d323f155…:f003318e…:call-api
判定:REPRODUCED:同逻辑步骤两次执行键不同(外部去重失效)
修复方向(供 owner 裁决,未实现任何代码)
矛盾本质:#320「终态行不得声明未完成的工作」(next_step 同清)与 #322「重投读同一行 ⇒ 同 token」在 error→retry 路径互斥。候选:
- a) error 行豁免 next_step 清除(违 #320 不变量字面,需在不变量文本里给 error+retry 语义开口子);
- b) 终态化时把将被重跑节点的 token 存入
state.error扩展键或专字段,retry_wakeup 优先复用而非重铸; - c) retry_wakeup 判据改锚(如以 noderetry 计数键世代推 token)——与「token 不可推导」的防伪造设计冲突,估计不可取。
倾向 b:不动 #320 不变量,token 随失败证据一起落盘。
验收建议
负控:构造节点首跑带 T1 外发收据后失败 → retry 唤醒 → 断言重跑绑定 token == T1(现树必红);同键后外部去重生效的端到端断言。
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- Avg merge
- 1h 55m
- Merged PRs (30d)
- 13
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from jeffkit/plaita
-
enhancement
Difficulty 4/5 1-2 days Newbie friendliness 43/100
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
jeffkit/plaita#305 · 4 comments ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
nansencenter/geodataset#39 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
awslabs/visual-asset-management-system#804 ·
Maintainers usually reply within 1 day
-
follow-up
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
odoo/odoo#297927 · 1 comment ·
Maintainers usually reply within 1 day
-
link-rot
Difficulty 1/5 Under an hour Newbie friendliness 67/100