From a81db16cdd359a8d0224f201f72bad0d4ede17e7 Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 19 Sep 2026 05:03:01 +0000 Subject: [PATCH] fix(server): thread request ctx through session bootstrap, drop Background DB calls - getOrCreateSession now takes ctx; GetSessionOwnerID/ RestoreSessionContext/CompilePromptGuidance run under context.WithTimeout(5s) instead of context.Background() - SyncRecentDialogue's rolling summary uses a 30s timeout context instead of Background, so client disconnect cancels the LLM call Co-authored-by: Cursor --- internal/chat/session.go | 4 +++- internal/server/handlers.go | 3 ++- internal/server/server.go | 16 +++++++++++++--- internal/server/sse.go | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/internal/chat/session.go b/internal/chat/session.go index b9085212..af294a82 100644 --- a/internal/chat/session.go +++ b/internal/chat/session.go @@ -176,7 +176,9 @@ func (s *Session) SyncRecentDialogue() { // 若发生了截断且存在早期消息,同步计算或加载滚动摘要 if truncated && len(early) > 0 && s.CtxMgr != nil { - s.syncDialogueSummary(context.Background(), early) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + s.syncDialogueSummary(ctx, early) } } diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 3ba026c6..51f123c3 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -143,7 +143,7 @@ func (s *Server) handleGetProject(w http.ResponseWriter, r *http.Request) { return } - sess, err := s.getOrCreateSession(0, sessionID, "", "", "", "", "", "", "", "") + sess, err := s.getOrCreateSession(r.Context(), 0, sessionID, "", "", "", "", "", "", "", "") if err != nil || sess == nil || sess.UserCtx == nil { writeSafeError(w, r, http.StatusNotFound, "session or project context not found") return @@ -170,6 +170,7 @@ func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) { req.WorkDir = "" sess, err := s.getOrCreateSession( + r.Context(), user.ID, req.SessionID, req.ProjectName, diff --git a/internal/server/server.go b/internal/server/server.go index b2caff30..c98f2976 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -403,6 +403,7 @@ func (s *Server) cleanStaleSessionsLocked(ttl time.Duration) int { // getOrCreateSession 获取或动态构建会话。callerUserID>0 时校验持久层归属,不匹配返回 ErrSessionOwnerMismatch。 func (s *Server) getOrCreateSession( + ctx context.Context, callerUserID int64, sessionID string, projectName string, @@ -420,7 +421,10 @@ func (s *Server) getOrCreateSession( // 归属校验必须先于任何缓存命中/持久层灌入 if callerUserID > 0 && s.ctxMgr != nil { - if owner, err := s.ctxMgr.GetSessionOwnerID(context.Background(), sessionID); err == nil && owner > 0 && owner != callerUserID { + dbCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + owner, err := s.ctxMgr.GetSessionOwnerID(dbCtx, sessionID) + cancel() + if err == nil && owner > 0 && owner != callerUserID { return nil, ctxmgr.ErrSessionOwnerMismatch } } @@ -455,7 +459,10 @@ func (s *Server) getOrCreateSession( // 尝试从持久层恢复会话上下文 (服务重启后跨进程保持 G3) var restored *ctxmgr.RestoredSessionContext if s.ctxMgr != nil { - if r, err := s.ctxMgr.RestoreSessionContext(context.Background(), sessionID); err == nil && r != nil && len(r.Messages) > 0 { + dbCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + r, err := s.ctxMgr.RestoreSessionContext(dbCtx, sessionID) + cancel() + if err == nil && r != nil && len(r.Messages) > 0 { restored = r } } @@ -563,7 +570,10 @@ func (s *Server) getOrCreateSession( } if sess.UserID > 0 && sess.CtxMgr != nil { - if guidance, err := sess.CtxMgr.CompilePromptGuidance(context.Background(), sess.UserID); err == nil && guidance != "" { + dbCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + guidance, err := sess.CtxMgr.CompilePromptGuidance(dbCtx, sess.UserID) + cancel() + if err == nil && guidance != "" { _ = coordinator.ApplyContextUpdate(userCtx, coordinator.ContextUpdate{ ExpectedVersion: userCtx.Version, SetPersonalizedGuidance: true, diff --git a/internal/server/sse.go b/internal/server/sse.go index ae720088..84d066c9 100644 --- a/internal/server/sse.go +++ b/internal/server/sse.go @@ -174,6 +174,7 @@ func (s *Server) handleChatStream(w http.ResponseWriter, r *http.Request) { // 会话与项目绑定必须在 SSE headers/Flush 之前完成授权(与 tasks/run/stream 对齐) sess, err := s.getOrCreateSession( + r.Context(), user.ID, req.SessionID, req.ProjectName,