W
AI-Wiki
CONCEPT

SessionEnd

定义

SessionEndclaude-mem 五阶段 Hook 生命周期中的第 5 个阶段,也是会话结束时的清理阶段。它对应的执行脚本是 cleanup-hook.js,用于在 Claude Code 会话结束时,把当前 session 标记为已完成,并执行 graceful cleanup,而不是粗暴中断仍在运行的后续处理。

在本文档中的语境

在本文档描述的 Hook 执行流中,SessionEnd 位于 Stop/摘要生成之后的最终收尾位置,属于整个 Session Lifecycle 的退出阶段。

它的触发条件非常明确:

  • Claude Code session 结束时触发。
  • 不会/clear 时触发。
  • 它是退出时的清理钩子,不负责生成摘要,也不负责保存 observation;这些职责分别属于 summary-hook.jsPostToolUse 对应流程。

这意味着 SessionEnd 不是“清空上下文”的响应器,而是“结束会话”的完成标记器。

核心机制

1. 将 session 标记为 completed

SessionEnd 的首要动作,是在数据库中把当前 session 标记为 completed。原文给出的新方案可概括为:

SessionEnd → UPDATE sessions SET completed_at = NOW()

这里的关键不是立即删除任何运行中资源,而是通过写入完成状态,让后续组件能够感知“该会话已经结束,应进入自然收尾流程”。

2. 允许 worker 完成剩余处理

被标记完成后,worker 不会被立即强制终止;相反,它会看到该 session 已完成,然后继续把尚未处理完的工作做完,最后自然退出。

这正是文档强调的 graceful completion:

  • worker 可以完成重要操作;
  • 尚未落库或尚未汇总的处理有机会收尾;
  • 退出不依赖暴力中断,而是依赖状态转换。

3. 执行 graceful cleanup

SessionEnd 的清理策略不是“立刻删、立刻停”,而是“标记完成 → 允许剩余处理结束 → 再退出”。这就是本文档中所谓的 graceful cleanup。

它的目标包括:

  • 保持状态迁移干净;
  • 避免处理中任务被截断;
  • 为摘要生成和 observation 处理留出完成时间。

配置位置

SessionEnd 在 Hook 配置中通过命令方式调用 cleanup-hook.js

{
  "hooks": {
    "SessionEnd": [{
      "hooks": [{
        "type": "command",
        "command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js"
      }]
    }]
  }
}

在执行时序表里,SessionEnd 的特征是:

  • Timing:On exit
  • Blocking:No
  • Timeout:120s
  • Output Handling:Log only

也就是说,它发生在退出时,不阻塞主流程,超时时间为 120 秒,其输出主要用于日志而不是上下文注入或用户可见消息。

与旧方案的差异

旧方案(v3):激进清理

旧做法是:

SessionEnd → DELETE /worker/session → Worker stops immediately

这种 aggressive cleanup 会直接向 worker 发送删除/终止语义,导致 worker 立刻停下。

原文明确列出了这种做法的问题:

  • 会中断摘要生成;
  • 会丢失待处理 observation;
  • 会引入 race conditions。

新方案(v4.1.0+):优雅完成

从 v4.1.0+ 开始,策略改为 graceful completion:

  • 不再向 worker 发送 DELETE;
  • 改为在数据库中将 session 标记完成;
  • worker 检测到完成状态后,自行收尾并自然退出。

这项设计决策在文档中被明确总结为:

  • ✅ Graceful completion(v4.1.0+)
  • ✅ No longer sends DELETE to workers
  • ✅ Skips cleanup on /clear commands
  • ✅ Preserves ongoing sessions

其中“Preserves ongoing sessions”指的是:如果只是 /clear,系统不会把它误当作会话真正结束,更不会提前清理掉仍应保留的在途处理。

细节与边界

不在 /clear 时触发

这是 SessionEnd 最重要的边界之一。文档明确写明:它在 session ends 时触发,not on /clear

因此:

  • /clear 不等于会话结束;
  • /clear 不应触发会话完成标记;
  • /clear 不应导致 worker 被错误清理。

这个边界直接避免了“用户只是清屏/清上下文,却被系统当成彻底结束会话”的误判。

不负责摘要生成本身

虽然 SessionEnd 的设计会保护摘要生成不被中断,但它自己不生成摘要。摘要生成属于 Stop 阶段,对应脚本是 summary-hook.js,并且会把结果存入 session_summaries

换言之,SessionEnd 和摘要流程的关系是:

  • SessionEnd 负责收尾与完成标记;
  • summary-hook.js 负责 AI 摘要压缩;
  • graceful cleanup 的一个重要收益,是让摘要流程更有机会顺利完成。

非阻塞退出钩子

在 Hook Timing 表中,SessionEnd 被标记为 Non-blocking。这说明它虽然发生在退出时,但不是用来卡住主交互流程的同步终止器,而是偏向后台收尾控制的生命周期信号。

设计收益

采用 SessionEnd 的优雅完成策略后,文档列出的收益包括:

  • worker 能完成关键操作;
  • 摘要可以成功完成;
  • 状态转换更干净。

把这些收益放回整个架构里看,SessionEnd 的真正作用不是“结束得更快”,而是“结束得更正确”。它通过 completed 状态把退出动作从“强杀进程”改成“显式声明生命周期已结束”,从而与 Worker Service Architecture 更好协同。

相关条目