feat(session): 重构会话服务支持节点维度的Redis缓存管理

This commit is contained in:
2026-06-10 16:48:35 +08:00
parent 40abf0f606
commit df26329836
3 changed files with 75 additions and 46 deletions

View File

@@ -13,13 +13,13 @@ import (
)
const (
// RedisKeySessionHistory 会话历史缓存 key: session:history:{tenantId}:{sessionId}
RedisKeySessionHistory = "session:history:%d:%s"
// RedisKeySessionHistory 会话历史缓存 key: session:history:{tenantId}:{sessionId}:{nodeId}
RedisKeySessionHistory = "session:history:%d:%s:%s"
)
// formatRedisKey 格式化 Redis key
func formatRedisKey(tenantID uint64, sessionID string) string {
return fmt.Sprintf(RedisKeySessionHistory, tenantID, sessionID)
func formatRedisKey(tenantID uint64, sessionID, nodeID string) string {
return fmt.Sprintf(RedisKeySessionHistory, tenantID, sessionID, nodeID)
}
// ============================================
@@ -27,8 +27,8 @@ func formatRedisKey(tenantID uint64, sessionID string) string {
// ============================================
// SaveToRedis 保存一轮对话到 Redis ZSET
func SaveToRedis(ctx context.Context, tenantID uint64, sessionID string, round *dto.HistoryRound) error {
key := formatRedisKey(tenantID, sessionID)
func SaveToRedis(ctx context.Context, tenantID uint64, sessionID, nodeID string, round *dto.HistoryRound) error {
key := formatRedisKey(tenantID, sessionID, nodeID)
maxRounds := util.GetMaxRounds(ctx)
expireSeconds := int64(util.GetExpireMinutes(ctx) * 60)
@@ -52,10 +52,22 @@ func SaveToRedis(ctx context.Context, tenantID uint64, sessionID string, round *
return nil
}
// DeleteRedisMessages 批量删除 Redis 中多条消息按消息ID列表
func DeleteRedisMessages(ctx context.Context, tenantID uint64, sessionID string, msgIDs []int64) error {
key := formatRedisKey(tenantID, sessionID)
// DeleteSessionHistory 删除整个 session 下所有 node 的缓存
func DeleteSessionHistory(ctx context.Context, tenantID uint64, sessionID string) error {
pattern := fmt.Sprintf(RedisKeySessionHistory, tenantID, sessionID, "*")
keys, err := g.Redis().Do(ctx, "KEYS", pattern)
if err != nil {
return err
}
for _, key := range keys.Strings() {
_, _ = g.Redis().Do(ctx, "DEL", key)
}
return nil
}
// DeleteRedisMessages 批量删除指定 node 下的消息
func DeleteRedisMessages(ctx context.Context, tenantID uint64, sessionID, nodeID string, msgIDs []int64) error {
key := formatRedisKey(tenantID, sessionID, nodeID)
for _, msgID := range msgIDs {
cursor := "0"
for {
@@ -64,42 +76,29 @@ func DeleteRedisMessages(ctx context.Context, tenantID uint64, sessionID string,
g.Log().Warningf(ctx, "[会话Redis] ZSCAN失败 msgID=%d err=%v", msgID, err)
break
}
parts := result.Strings()
if len(parts) < 2 {
break
}
cursor = parts[0]
for _, member := range parts[1:] {
if _, err := g.Redis().Do(ctx, "ZREM", key, member); err != nil {
g.Log().Warningf(ctx, "[会话Redis] ZREM失败 err=%v", err)
}
_, _ = g.Redis().Do(ctx, "ZREM", key, member)
}
if cursor == "0" {
break
}
}
}
return nil
}
// DeleteSessionHistory 删除整个会话的 Redis 缓存
func DeleteSessionHistory(ctx context.Context, tenantID uint64, sessionID string) error {
key := formatRedisKey(tenantID, sessionID)
_, err := g.Redis().Do(ctx, "DEL", key)
return err
}
// ============================================
// 读操作
// ============================================
// GetFromRedis 从 Redis ZSET 获取会话历史,返回 HistoryRound 切片
func GetFromRedis(ctx context.Context, tenantID uint64, sessionID string) ([]dto.HistoryRound, error) {
key := formatRedisKey(tenantID, sessionID)
// GetFromRedis 从 Redis ZSET 获取会话历史
func GetFromRedis(ctx context.Context, tenantID uint64, sessionID, nodeID string) ([]dto.HistoryRound, error) {
key := formatRedisKey(tenantID, sessionID, nodeID)
maxRounds := util.GetMaxRounds(ctx)
result, err := g.Redis().Do(ctx, "ZREVRANGE", key, 0, maxRounds-1)
@@ -118,7 +117,6 @@ func GetFromRedis(ctx context.Context, tenantID uint64, sessionID string) ([]dto
// 解析
// ============================================
// parseRounds 解析 Redis ZSET members 为 HistoryRound 切片
func parseRounds(members []string) []dto.HistoryRound {
rounds := make([]dto.HistoryRound, 0, len(members))
for _, member := range members {