会话存储恢复

Hermes 把每个 profile 的所有对话保存在一个 SQLite 文件 state.db 中,另有 SQLite 自行管理的两个附属文件:state.db-wal(写前日志)和 state.db-shm。多个 Hermes 进程可以安全地共享该文件——网关、桌面应用、仪表盘、cron 和 CLI 命令都通过 SQLite 自己的锁来写入。

有一件事是不安全的:在另一个进程正在写入时重写存储。一旦发生这种情况,那些仍持有日志旧副本的进程会主动停止写入,每一轮都回复类似这样的消息:

另一个 Hermes 进程仍持有会话数据库写前日志的旧副本,因此 Hermes 已停止写入以保护文件……

本页就是这条消息所链接到的指南。看到它时什么都没有丢失;这个拒绝恰恰是为了什么都不丢失。

三步修复

  1. 退出该 profile 上的每一个 Hermes 进程。 桌面应用、网关、仪表盘、cron:

    hermes gateway stop          # 命名 profile 加 -p <profile>
    

    然后从菜单退出桌面应用,并停掉任何仪表盘(hermes dashboard --stop)或你自跑的自定义服务。只重启其中一个是不够的——只要还有一个进程持有旧日志,所有新进程都会继续拒绝。

  2. 让 doctor 检查谁还持有日志。

    hermes doctor                # 命名 profile 加 -p <profile>
    

    只要还有任何进程持有已退役的日志,doctor 就会把每个持有者打印为 PID N (命令) 并给出同样的修复方法,同时跳过它的健康检查和任何 --fix 工作,以免它自己变成又一个写入者。停掉列出的进程并重跑,直到那行提示消失。

  3. 重新启动 Hermes(先启动一个进程——网关或桌面应用),再发一次消息。你的对话从断点处继续。

不要做

  • 不要在进程运行时运行 hermes doctor --fix。 当 doctor 能看到有进程持有已退役日志时,它会拒绝执行检查点;但在一台它无法检视进程的宿主机上,那条修复路径恰恰就是引发问题的第二个写入者。
  • 不要删除 state.db-wal 或 state.db-shm。 日志里保存着尚未写入 state.db 的已提交对话。删除它是唯一会把"拒绝"变成真正数据丢失的操作。
  • 不要单独复制 state.db。 这三个文件是一个整体镜像。用快照(hermes backup)或 hermes sessions recover,绝不要 cp state.db somewhere/。
  • 不要让 agent 去修。 agent 自己的会话就在同一个存储里;它会撞上同样的拒绝。

维护命令在有人写入时会拒绝

hermes sessions optimize、hermes sessions optimize-storage 和 hermes sessions prune 会重写存储(VACUUM、重建全文索引、批量删除)。在一个运行中的网关下运行其中之一,正是一群 agent 最终陷入上述拒绝的原因,因此它们现在会先检查,并在另一个进程持有数据库时拒绝执行:

拒绝执行 `hermes sessions optimize-storage`:另一个进程正在使用 ~/.hermes/state.db。
  PID 41230 (hermes gateway run):state.db、state.db-shm、state.db-wal
  PID 41355 (hermes serve --profile work):state.db-wal
在有活跃写入者时重写数据库,正是每个 agent 最终因已退役的 state.db-wal 错误而拒绝轮次的原因。什么都没有丢失。
先停掉它们(`hermes gateway stop`、退出桌面应用、暂停 cron),再重新运行。
如接受风险,可用 --force 覆盖。

--dry-run 预览永远不会被阻断。--force 会照常运行——仅当你确认列出的进程都空闲时才用它(例如你自己启动的一个只读进程)。在桌面控制台中输入 sessions optimize 时也会运行同样的检查。

你可能在 state.db 旁边看到的文件

文件或目录是什么该怎么做
state.db-wal、state.db-shmSQLite 活跃的写前日志及其共享内存索引。网关或桌面应用运行时 -wal 很大是正常的。别碰。下次检查点时它会自行收缩。
state.db.retired-wal-<timestamp>-<pid>/Hermes 在拒绝写入时,对某个进程仍持有的日志副本所做的捕获,外加一份描述它的 manifest.json。这是取证证据,不是你盲目恢复的备份。保留它。如果恢复后事故前不久的对话不见了,把这个目录附到 bug 报告里;维护者能从 manifest.json 判断这些帧是否应叠加到当前文件之上。
state.db.pre-update-emergency-<timestamp>.bak桌面更新器在触碰存储前所拍的快照。在你用了一段时间新版应用后再保留。仅在所有 Hermes 进程都停止时恢复:先 hermes sessions recover --source <file> --inspect-only。
state.db.corrupt.<timestamp>.bak、*.malformed-backupHermes 在修复或隔离某文件前发现其损坏时所做的副本。不要把它们恢复覆盖到 state.db 上——它们带着同样的损坏。保留备查;恢复正常后可安全删除。
state-snapshots/hermes update 和 hermes backup 所拍的快速快照。在所有 Hermes 进程停止时恢复;参见 hermes backup。

三步仍不奏效时

如果所有 Hermes 进程都已停止,hermes doctor 不再列出持有者,而你启动网关时它仍拒绝写入,那文件本身可能已损坏。再次停掉一切,只读检查而不写入:

hermes sessions recover --source ~/.hermes/state.db --inspect-only

--inspect-only 绝不修改文件。如果它报告存储可恢复,按它打印的命令操作,或从 state-snapshots/ 恢复最新快照。这一切背后的机制见开发者指南:State DB recovery 和会话存储。