fix(keeper): 评论任务对「已关闭 issue」永不收尸——3 条陈尸占满 comment_max_in_flight=3,全仓人类评论自动回评自 10-04 停摆
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 58/100
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
优先级 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 句柄)。
- Lingua principale
- Python
- Stelle
- 0
- Fork
- 0
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Preparare l'ambiente
Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di jeffkit/issue-keeper
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 15/100
jeffkit/issue-keeper#22 · 3 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
jeffkit/issue-keeper#21 · 3 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
jeffkit/issue-keeper#17 · 6 commenti ·
-
keeper-ignore
Difficoltà 5/5 Più di una settimana Idoneità per principianti 20/100
jeffkit/issue-keeper#16 · 2 commenti ·
-
Difficoltà 4/5 3-5 giorni Idoneità per principianti 35/100
jeffkit/issue-keeper#11 · 5 commenti ·
Tutte le issue di jeffkit/issue-keeper
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
khuisman/mcp-gee-sweet#1166 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
lugassawan/swe-workbench#823 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
gramaziokohler/compas_timber#870 ·
-
security-scan-failure
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
semantica-agi/semantica#2089 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
autowarefoundation/autoware_carla_scenario#500 ·
I maintainer di solito rispondono entro 1 giorno