Skip to content

fix(minimax-bot): 删会话失败时不再顺手把聊天记录清空 - #135

Open
Apageoflove wants to merge 1 commit into
MiniMax-AI:mainfrom
Apageoflove:fix/minimax-bot-reset-order
Open

Apageoflove wants to merge 1 commit into
MiniMax-AI:mainfrom
Apageoflove:fix/minimax-bot-reset-order

Conversation

@Apageoflove

@Apageoflove Apageoflove commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

删 Bot、删群、聊天里点 Start new chat,这三件事以前在写盘失败的时候会顺手把聊天记录毁掉。

它们走的是同一个 deleteChat。那里的顺序是先清空这条会话的 message 文件,再去写 state.json 把会话忘掉。第二步失败的时候第一步已经落到磁盘上了,所以接口回 500,用户看到失败,会话还留在侧栏里,点进去是空的。再点一次也救不回来,文件已经是空的了。

复现用真实路由跑的。先给两个会话各塞三条消息,把 state.json 的位置换成一个目录让写入失败,然后分别走 DELETE /api/bots 和 POST /api/chats/:id/reset。在当前上游 main 上跑出来是这样:

DELETE /api/bots/bot_victim -> 500 {"error":"internal","message":"Something went wrong on the server. Try again later"}
POST /api/chats/bot:bot_reset/reset -> 500 {...同样的错误...}
Victim message file now: []   Reset message file now: []
after restart on the untouched state.json: Victim present=true, Reset present=true
   Victim messages: 0
   Reset  messages: 0

两个会话都还在,消息都是 0 条。同一份探针打到改过的代码上,最后两行变成 3 和 3。

改法就是把两个写的顺序换过来,先写那份不带这条会话的 state,成功了再清消息文件。两个写还在同一个队列槽里,没有别的写能插进来。失败时两边都没动,用户原样重试一次就行。

第一版我改得更随意些,先删内存里的 sessions 再写盘。reviewer 指出这样失败时内存已经跑到磁盘前面了,之后任何一次无关的保存都会把这个删除顺手落盘,会话游标就悄悄没了。现在改成先写一份去掉这条会话的快照,写成功才把它提交到内存。

测试加在 storage-reliability 里,把 state.json 换成目录让写失败,断言 message 文件里那条消息还在。这条在未改的上游上红,在切片上绿。全量 412 条过,上游基线 411 条。

没做断电和磁盘写满这类真实现场注入,失败都是靠把 state.json 的位置换成目录模拟的。deleteBot 里 memory.archive 和 store.save 的相对顺序没单独打探针,只读了代码确认它们在 deleteChat 之后。


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

删 Bot、删群、Start new chat 都走 deleteChat。它先清空这条会话的 message
文件,再写 state.json 把会话忘掉。第二步失败时第一步已经落盘,接口回 500、
会话仍在侧栏,点进去是空的,再点一次也救不回来。

顺序换过来:先写不带这条会话的 state,成功了再清消息文件,两个写仍在同一个
队列槽内。内存里的 sessions 条目也等写成功才提交,避免失败时内存领先磁盘、
被后续无关保存顺手落盘。

新测试把 state.json 换成目录让写失败,断言 message 文件里那条消息还在。
未改的上游上红、切片上绿。全量 412 条通过,上游基线 411 条。

Copy link
Copy Markdown
Collaborator

感谢修复!看了 1d0ac9b,有一个问题需要改了再合:

会丢 session 的竞态。 store.mjs:629-631 先取了 sessions 的快照,等写盘的 await 结束后,再用 this.state.sessions = sessions 整体替换。如果在这个 await 期间另一个会话第一次调用 setSession(:423 的 ??= 会在旧对象上新建条目),这个新条目会在替换时被覆盖。之后 save() 写盘时也没有它,内存和磁盘里就都丢了,那个会话下一轮会开一个新 session,之前的上下文接不上。我们用脚本复现过:在 1d0ac9b 上删除 A 的同时给 B 建 session,B 的 session 是 undefined;同样的脚本在父提交上,B 的 session 能保留。

建议改法:快照照常用来写盘,写成功后改用 delete this.state.sessions[chatId] 就地删除,不要整体替换对象。最好再补一个并发场景的测试。

另外两点不影响合并,供参考:

  • 注释里说「内存不会领先磁盘」,目前只对 sessions 成立。deleteBot/deleteGroup 在调用 deleteChat 之前就已经改了内存里的 bots/groups(team.mjs:324-338、:442-444),所以 state 写失败时,roster 在内存里会比磁盘新。这个问题之前就有,不是这次引入的,只是注释可以写得更准确。
  • 这个 PR 和 fix(minimax-bot): 重启后已收下的请求还能再发出去 #133 改的是同一批版本文件,后合的那个需要 rebase。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants