Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

fix(keeper): 评论任务对「已关闭 issue」永不收尸——3 条陈尸占满 comment_max_in_flight=3,全仓人类评论自动回评自 10-04 停摆

Aperta
#19 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
58/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
github, python
Ambito
backend, devtools

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。

验收条件(可断言):

  1. 单测:构造一个 processed=True、带 comment_tasks 的 item,不出现在 list_open 返回集里;跑一轮后断言该 comment_tasks 已被清除(或 _count_comment_tasks(state) == 0)。
  2. 回归单测:state 中预置 3 条"死 pid + 已关闭 issue"的 comment_tasks,随后一条新评论到达 → 断言仍然派发评论 agent(而不是打"已达上限")。
  3. 现网自愈:部署后上述 3 条记录消失且闸门计数归零,任一仓新留人类评论能收到自动回评——判据=日志出现 评论 agent 完成 (comment=...) + 对应 issue 出现回评。
  4. 附带:新增一条 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

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di jeffkit/issue-keeper

Tutte le issue di jeffkit/issue-keeper

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.