// Package service - 会话服务 // 功能:用户会话管理、状态维护 package service import ( "context" "customer-server/dao" "gitea.com/red-future/common/jaeger" "gitea.com/red-future/common/rabbitmq" "gitea.com/red-future/common/redis" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/os/glog" ) // sessionService 会话服务(操作 session 表) type sessionService struct{} // SessionService 会话服务单例 var SessionService = new(sessionService) // ============== RabbitMQ 消费者(归档延时消息)============== // SessionArchiveConsumer 会话归档消费者 type SessionArchiveConsumer struct { consumer *rabbitmq.Consumer } // NewSessionArchiveConsumer 创建会话归档消费者 func NewSessionArchiveConsumer(ctx context.Context) *SessionArchiveConsumer { queueName := GetConfigString(ctx, "archive.queue") return &SessionArchiveConsumer{ consumer: rabbitmq.NewConsumer(queueName, handleSessionArchive), } } // Start 启动消费者 func (c *SessionArchiveConsumer) Start(ctx context.Context) (err error) { glog.Info(ctx, "会话归档消费者启动...") return c.consumer.Start(ctx) } // Stop 停止消费者 func (c *SessionArchiveConsumer) Stop(ctx context.Context) { c.consumer.Stop(ctx) } // handleSessionArchive 处理会话归档消息 func handleSessionArchive(ctx context.Context, body []byte) (err error) { ctx, span := jaeger.NewSpan(ctx, "consumer.session.archive") defer span.End() var msg redis.ArchiveMessage if err = gjson.DecodeTo(body, &msg); err != nil { jaeger.RecordError(ctx, err, "解析归档消息失败") return } glog.Infof(ctx, "收到归档消息 - 用户: %s, Session: %s", msg.UserId, msg.SessionId) // 检查用户是否在归档发送后有活跃(60分钟内) isActive, err := redis.IsUserActive(ctx, msg.UserId, int64(redis.GetArchiveDelay())) if err != nil { jaeger.RecordError(ctx, err, "检查用户活跃状态失败") return } if isActive { glog.Infof(ctx, "用户 %s 在归档期间有活跃,跳过归档", msg.UserId) return } // 执行归档 if err = dao.Session.Archive(ctx, msg.UserId, msg.SessionId); err != nil { jaeger.RecordError(ctx, err, "归档会话失败") return } // 清除 Session 缓存(需要tenantId) // TODO: ArchiveMessage需要添加TenantId字段 redis.DelSessionCache(ctx, msg.TenantId, msg.UserId) glog.Infof(ctx, "会话已归档 - 用户: %s, Session: %s", msg.UserId, msg.SessionId) return }