Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

fix(worker): 节点重试预算键被「任一节点成功」反复清零——确定性失败节点无限重投、执行永不终态

Closed
#73 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
50/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
backend

Research direction

Start in plaita/server/flow_worker.py: _reset_node_retry_counter (around lines 618-633) is called unconditionally after any node advances, near line 1851, and _node_failure_retry_decision (around lines 637-672) increments the same key. Keep the G1 manual-retry reset near line 1639 unchanged. Build a flow where node X always fails, node Y always succeeds and loops back to X, then check that the retry counter reaches 5/5, 'node retry budget exhausted' is logged once, and the execution ends in error.

Written by the indexing model from the issue text.

Description

优先级 P1 · 依赖:无

基线 HEAD = 65f48f2

Summary

节点重试预算的计数键会被「任一节点成功推进」清零,于是「确定性失败 + 环回重投」的节点永远拿不回累积值——每次重投都从 1/5 重新起算,预算耗尽分支从未触发,执行可以无限重投而不终态。

  • 代码证据:plaita/server/flow_worker.py:1851——每一次 run_distributed 步进成功(任意节点)后无条件调用 _reset_node_retry_counter(execution_id);该函数(:618-633)DEL plaita:execution:noderetry:<execution_id>。而预算判定 _node_failure_retry_decision(:637-672)用的是同一键 INCR 后的值(:656)。即:不同节点的成功与同一节点的连续失败共享一个会被清空的键。
  • 运行期证据(计数分布):2026-10-09 本机 worker-mac.log 中 第 N/5 次重试 的出现次数为 1/5 × 598,2/5/3/5/4/5/5/5 × 0;全日志 节点重试预算耗尽 × 0。
    grep "2026-10-09" ~/.plaita-console/worker-mac.log | grep -oE "第 [0-9]/5 次重试" | sort | uniq -c
    grep -c "节点重试预算耗尽" ~/.plaita-console/worker-mac.log   # → 0
    
  • 运行期证据(键不累积):对当时正在循环的执行 fbc93f1da1754a8d9a9c3ea8807930f4,60 秒内每 3 秒 GET plaita:execution:noderetry:fbc93f1da1754a8d9a9c3ea8807930f4 → 全程 nil;同窗口 grep -c "执行 fbc93f1d… 节点执行失败" 前后差 = 1(确实失败了一次)。失败发生了,计数键却不存在。
  • 触发场景:impl 节点确定性失败(本次诱因是 GLM 5 小时限额:HTTP 429 {"error":{"code":"1308","message":"[1308][已达到 5 小时的使用上限。您的限额将在 2026-10-09 18:11:22 重置。]"}})。重投的同体新副本被 worker 重放时,同一次 run_distributed 里仍有别的节点推进成功(pre/gates/分支/错误处理节点)→ 键被清零 → impl 再次失败时又从 1/5 起算。

影响

  • 瞬态故障 → 无界重投风暴:任何一个节点的确定性失败(provider 429/401、依赖不一致、门恒红)都能让 execution 永远停在 running,keeper 收不到终态、在途槽位不释放、DLQ/日志/账目全被污染。
  • 今日实测代价:6 个在途 run 持续 90 分钟零落地(近 90min 28 次派发 / 0 落地),worker-mac.log 胀到 8.8MB(AgentRunError: executor 'recursive' exited 1 2387 次、exited 143 539 次),并向 GLM 持续打 429;pipeline_max_in_flight=6 的槽位被 6 个永不收敛的执行长期占满。
  • 预算机制形同虚设:设计意图是「连续失败 5 次即终态化」,实际 0 次触发;失败只能靠别处(人工 cancel / zombie reap)终结。

建议

  • 预算键改按 (execution_id, node_id) 计,且只在该节点自身成功推进时清零;或在此之外加一条「同一执行累计重投次数」上限(与节点维度独立,防环回场景绕过)。
  • 保留现有语义:G1 人工 retry 唤醒时的清零(:1639)不变——那是「拿全新预算」,与本缺陷无关。
  • 验收(可断言):
    1. 构造「节点 X 恒失败、节点 Y 恒成功且流程环回 X」的 flow,投递执行 → 断言 X 的计数键达到预算值、日志出现恰好一次 节点重试预算耗尽、执行终态化 error;
    2. 同用例重复投递 → 断言不再出现 第 1/5 次重试 无限循环(重投次数有界);
    3. 回归:不同节点交替失败的场景中,节点 B 的首次失败仍应拿到完整预算(现注释所述意图不变)。

边界

  • 本单只针对「预算键被非本节点的成功清零」。相邻缺陷另单:编号 50(重投载体被租约冲突 ack 吃掉)、编号 52(重试耗尽后 console 终态滞后)、编号 47(reclaim 不查活跃租约的 churn)——机制不同,不合并。
  • 不改队列层 delivery_count 语义(task_queue.py reclaim 上报的是 XCLAIM 前的 times_delivered,本单沿用 worker 侧计数键的设计选择)。
Dominant language
Python
Stars
0
Forks
1
Avg merge
3h 53m
Merged PRs (30d)
3

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from jeffkit/plaita

All issues in jeffkit/plaita

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.