fix(keeper): 评论任务对「已关闭 issue」永不收尸——3 条陈尸占满 comment_max_in_flight=3,全仓人类评论自动回评自 10-04 停摆
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 58/100
調査の方向性
Start with issue_keeper/keeper.py, especially _count_comment_tasks, _collect_comment_tasks, _process_resource, and the round-level pipeline cleanup; then read issue_keeper/sources/github.py around the open-resource listing and the relevant tests. Reproduce the case with a processed item carrying comment tasks that is absent from list_open, and verify a run clears the orphaned tasks and still dispatches a new comment agent. Confirm cleanup is observable without changing the configured concurrency limit.
索引モデルが issue の本文から書いたものです。
説明
优先级 P1 · 依赖:无
基线 HEAD = 1b5dea0
Summary
「人类评论自动回评」自 2026-10-04 起全仓停摆:state 中 3 条评论异步任务陈尸(进程早死、所属 issue 已关闭)被 _count_comment_tasks 一直计入,占满全局闸 comment_max_in_flight=3,此后任何仓的任何新评论都不再派发评论 agent。停摆是静默的(无 ERROR、gate 提示是 INFO)。
证据 1 — 3 条陈尸记录(远端 ~/.issue-keeper/state.json 实读),三条均 attempts:1、pid 早死:
| 仓 & 单 | comment id | pid | started_at(UTC) |
issue 关闭时刻(UTC) |
|---|---|---|---|---|
jeffkit-browser-bridge #2 |
IC_kwDOUS-An88AAAABZFYsgg |
29121 | 2026-10-04 09:10:24 | 09:14:33 |
jeffkit-ilink-hub #29 |
IC_kwDOSxmvrc8AAAABZF1GDg |
11930 | 2026-10-04 11:07:53 | 11:17:09 |
jeffkit-ilink-hub #27 |
IC_kwDOSxmvrc8AAAABZF1EBw |
12482 | 2026-10-04 11:08:05 | 11:32:10 |
三单 git/gh 实核均为 CLOSED;三个 pid 在 VM 上已不存在(ps -p 29121/11930/12482 全空;VM 于 10-05 23:35 重启,pid 空间早已重置)。共同特征:评论 agent 派发后 4~24 分钟内 issue 被关闭。
证据 2 — 计数不问死活也不问 open(issue_keeper/keeper.py:1576-1582):
def _count_comment_tasks(state) -> int:
"""全局在途评论任务数(跨仓;按任务记录计数——死任务由收尸清除)。"""
n = 0
for rs in state.repos.values():
for it in rs.items.values():
n += len(getattr(it, "comment_tasks", None) or {})
return n
注释里「死任务由收尸清除」的前提在下面的证据 4 里不成立 → 记录永久留存 → 恒返 3。
证据 3 — 闸门与默认值(keeper.py:739-741 + config.py:277):
if _count_comment_tasks(state) >= max(1, config.comment_max_in_flight):
log.info("[%s] 评论 agent 并发已达上限 (%d),本轮不派发新评论", ...)
return handled
默认 comment_max_in_flight: int = 3;远端 ~/.issue-keeper/config.yaml 无该键(反证:grep -n comment_max_in_flight ~/.issue-keeper/config.yaml 零命中)⇒ 生效值恰为 3,与 3 条陈尸相等 ⇒ 容量恒为 0,不是"减少"而是"清零"。
证据 4 — 唯一收尸入口只服务于 open 资源:全仓 grep -n comment_tasks issue_keeper/keeper.py 显示 _collect_comment_tasks 只有一个调用点(keeper.py:682),位于 _process_resource() 内;而 _process_resource 只被 keeper.py:502 的 for res in resources: 调用,resources 来自 keeper.py:489 src.list_open(binding.repo, [kind], labels) —— GitHub 适配器里该调用固化为 --state open(issue_keeper/sources/github.py:170-176):
args = [kind, "list", "--repo", repo, "--state", "open", ...]
⇒ issue 一旦关闭就永远不再进入 _process_resource,其 comment_tasks 记录再也没有任何代码路径去收(items 记录本身留在 state 里,repos/items 不会被清理)。这不是超时逻辑失效,而是一条结构性的孤儿路径:收尸只发生在"资源被再次扫描到"时。
证据 5 — 日志量级(远端 ~/.issue-keeper/keeper.log,覆盖 2026-10-06 00:47 至今):
评论 agent 并发已达上限:486 条(首条 2026-10-07 19:47:18 ·recursive#134;末条 2026-10-08 17:59:38 ·plaita#50)评论 agent 完成:1 条(2026-10-06 02:49 lavs#19)评论 agent 无输出,已自动重试:1 条(2026-10-06 02:43 lavs#19)
(日志起点晚于陈尸产生时间 10-04,故"停摆起点"由证据 1 的 started_at + 关闭时刻推定;日志只用于量级佐证。)
影响
谁踩:任何在 jeffkit/* 九仓里留评论的人(含人工协调线程的 okguitar/jeffkit)——评论进去以后永远不会被自动回评,且不会报错:state 健康、keeper 每轮"处理 0 条"正常退出、只有一条 INFO 级 gate 日志。停摆已持续 4 天。
代价:①人机协作闭环断在我方(评论→回评→验收→关闭)的第一步,值守/提报方只能靠人工发现"没人理我";②3 个全局槽位长期被无法自愈的僵尸占满,即使没有本次泄漏,任何一个"派发后立刻关闭"的 issue 都会永久吃掉 1 个槽位(最坏 3 次即全停)——这是一条可复现的慢性容量泄漏,本次只是刚好一次踩满;③comment agent 的派发/完成/重试三条日志在停摆期近乎零,掩盖了故障(观测面上"没有异常")。
注意:本条与已关闭的 #7(收尾只发生在轮首一次)不同——#7 是时序窗口问题,本条是闭合态资源不再被访问导致的永久孤儿,与轮次时机无关。
建议
任选其一或组合(建议 a 为主、b 为兜底):
(a) 收尸与 open 状态解耦:每轮开头(与 _reap_pipelines 同处)加一遍全量 items 扫,对不在 open 列表里的 item 收 comment_tasks(只收尸、不回评亦可:进程已死且 issue 已关闭,回评发在关闭单上无意义——但必须清记录)。
(b) 计数改为按存活计:_count_comment_tasks 只统计 _comment_proc_alive(pid) 为真的任务,或对超时/死进程记录在计数前先触发一次收尸;避免"状态账本"直接当"容量账本"。
(c) 关闭时收尾:keeper 观察到资源终态(关闭)时顺手收掉其 comment_tasks。
验收条件(可断言):
- 单测:构造一个
processed=True、带comment_tasks的 item,不出现在list_open返回集里;跑一轮后断言该comment_tasks已被清除(或_count_comment_tasks(state) == 0)。 - 回归单测:state 中预置 3 条"死 pid + 已关闭 issue"的
comment_tasks,随后一条新评论到达 → 断言仍然派发评论 agent(而不是打"已达上限")。 - 现网自愈:部署后上述 3 条记录消失且闸门计数归零,任一仓新留人类评论能收到自动回评——判据=日志出现
评论 agent 完成 (comment=...)+ 对应 issue 出现回评。 - 附带:新增一条 INFO/DEBUG 日志,在收尸时区分"回评成功/死进程丢弃/关闭丢弃",使该路径可观测(当前完全静默)。
边界
- 不改
comment_max_in_flight默认值与语义(3 的配额本身合理,坏的是账本口径)。 - 不要求给已关闭 issue 补发 10-04 的历史回评(时效已过)。
- 与 #2、#17、#3、#5、#11 等既有单无依赖关系,可独立修。
未证实附注(推测,非结论)
_comment_proc_alive(keeper.py:1562-1573)在popen is None(跨重启接管路径)时退回os.kill(pid, 0)判活;pid 复用时会对一个陌生进程返回 True,随后keeper.py:1645-1652的超时分支会os.killpg(pid, SIGKILL)到不属于 keeper 的进程组。本次 3 条陈尸恰好走了"资源不再被访问"路径,未触发该分支,故未观察到实害;仅提示这条兜底判活值得一并加"pid 归属校验"(如比对启动时间 / 只信任 popen 句柄)。
- 主要言語
- Python
- スター
- 0
- フォーク
- 0
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
jeffkit/issue-keeper のほかの issue
-
難易度 4/5 3〜5日 初心者へのやさしさ 15/100
jeffkit/issue-keeper#22 · コメント 3 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
jeffkit/issue-keeper#21 · コメント 3 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
jeffkit/issue-keeper#17 · コメント 6 件 ·
-
keeper-ignore
難易度 5/5 1週間以上 初心者へのやさしさ 20/100
jeffkit/issue-keeper#16 · コメント 2 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
jeffkit/issue-keeper#11 · コメント 5 件 ·
jeffkit/issue-keeper の issue をすべて見る
似ている issue
-
question
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
conda-forge/vc-feedstock#132 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
limitlessprojects/Go-Hybrid#3342 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
UKGovernmentBEIS/inspect_ai#6268 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
LSSTDESC/rail_sompz#42 ·
-
All tests fail with 'EXITED with status 3' on pytest 9.2.0 (TestReport._id is not marshallable)オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
pytest-dev/pytest-forked#113 ·