Skip to content

fix(dag): httpapi exerciser teardown hang — DagSummaryPublisher event storm after dispose #316

Description

@LeXwDeX

现象(本地复现 + CI 实锤)

httpapi exerciser(bun run test:httpapi)在 summary 打印(pass=229 fail=0)之后进程不退出,挂起直至被 step timeout(15 分钟)杀掉。CI 实锤:PR #315 同 commit 两个 run 一红一绿(红 run 31994077328:summary 04:33:58 → step timeout 04:48:57,期间零输出)。本地抓网第一轮即复现(summary 后 120s 进程存活)。

挂起签名

挂起期间进程每 ~1.2 秒刷一条(dagID 各不相同、时间戳递减):

WARN DagSummaryPublisher: failed to publish summaries { dagID: dag_fe5ff1e2…, cause: … }

已定位的机制面

  • summary-publisher.ts:151-169:publisher 订阅 dag 触发事件,每个事件 forkIn(scope) 一个发布 fiber;发布体失败 → catchCause 打警告 → fiber 死亡
  • 警告流不止 = 拆伙期间仍有 dag 事件持续涌入;store 已 dispose → 发布必败
  • exerciser 尾段(index.ts:2154/2198):summary → Effect.scoped finalizer disposeApps()process.exit(0);挂点在 disposeApps 的 Promise.all(backend.ts:60 并行 dispose 全部 app)不返回
  • Memory 实例状态本身是纯 Map(memory.ts:91)、无后台 fiber——嫌疑在于装配图变化改变了 teardown 时序/事件流

归因线索

#313(Memory.node 进 server.ts app 图)合入前 15+ 个 ci-test run 全绿;合入后首个 dev run 绿,第二批次出现一红一绿。强相关,机制未钉死——需要:谁在 dispose 期间持续发 dag 事件、哪个 fiber/scope 未了结。

风险

不止测试路径:真实 server 关停同样走 dispose——若同款事件风暴存在,生产实例关停也会 hang。需确认。

复现

/tmp/opencode-repro/hang-catcher.sh(10 轮循环 + summary 后 120s 存活判定 + SIGQUIT 抓栈),第一轮命中。日志:/tmp/opencode-repro/loop-1.log

验收

  1. exerciser teardown 有界退出(summary 后 <60s 必 process.exit)
  2. 挂起根因证明(事件源 + 未了结 fiber 定位)
  3. 真实 server 关停路径确认不受同款风暴影响(或一并修复)
  4. flaky 消除验证:抓网脚本 10 轮无挂起

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions