session_limit_cache.go 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package service
  2. import (
  3. "context"
  4. "time"
  5. )
  6. // SessionLimitCache 管理账号级别的活跃会话跟踪
  7. // 用于 Anthropic OAuth/SetupToken 账号的会话数量限制
  8. //
  9. // Key 格式: session_limit:account:{accountID}
  10. // 数据结构: Sorted Set (member=sessionUUID, score=timestamp)
  11. //
  12. // 会话在空闲超时后自动过期,无需手动清理
  13. type SessionLimitCache interface {
  14. // RegisterSession 注册会话活动
  15. // - 如果会话已存在,刷新其时间戳并返回 true
  16. // - 如果会话不存在且活跃会话数 < maxSessions,添加新会话并返回 true
  17. // - 如果会话不存在且活跃会话数 >= maxSessions,返回 false(拒绝)
  18. //
  19. // 参数:
  20. // accountID: 账号 ID
  21. // sessionUUID: 从 metadata.user_id 中提取的会话 UUID
  22. // maxSessions: 最大并发会话数限制
  23. // idleTimeout: 会话空闲超时时间
  24. //
  25. // 返回:
  26. // allowed: true 表示允许(在限制内或会话已存在),false 表示拒绝(超出限制且是新会话)
  27. // error: 操作错误
  28. RegisterSession(ctx context.Context, accountID int64, sessionUUID string, maxSessions int, idleTimeout time.Duration) (allowed bool, err error)
  29. // RefreshSession 刷新现有会话的时间戳
  30. // 用于活跃会话保持活动状态
  31. RefreshSession(ctx context.Context, accountID int64, sessionUUID string, idleTimeout time.Duration) error
  32. // UnregisterSession 立即移除会话注册(不等待空闲超时)
  33. // 用于请求最终失败的场景:上游从未真正服务该会话,不应继续占用会话槽,
  34. // 否则 max_sessions 受限的账号会被失败请求的 session hash 卡满整个空闲窗口,
  35. // 导致后续新会话在超时窗口内全部被拒
  36. UnregisterSession(ctx context.Context, accountID int64, sessionUUID string) error
  37. // GetActiveSessionCount 获取当前活跃会话数
  38. // 返回未过期的会话数量
  39. GetActiveSessionCount(ctx context.Context, accountID int64) (int, error)
  40. // GetActiveSessionCountBatch 批量获取多个账号的活跃会话数
  41. // idleTimeouts: 每个账号的空闲超时时间配置,key 为 accountID;若为 nil 或某账号不在其中,则使用默认超时
  42. // 返回 map[accountID]count,查询失败的账号不在 map 中
  43. GetActiveSessionCountBatch(ctx context.Context, accountIDs []int64, idleTimeouts map[int64]time.Duration) (map[int64]int, error)
  44. // IsSessionActive 检查特定会话是否活跃(未过期)
  45. IsSessionActive(ctx context.Context, accountID int64, sessionUUID string) (bool, error)
  46. // ========== 5h窗口费用缓存 ==========
  47. // Key 格式: window_cost:account:{accountID}
  48. // 用于缓存账号在当前5h窗口内的标准费用,减少数据库聚合查询压力
  49. // GetWindowCost 获取缓存的窗口费用
  50. // 返回 (cost, true, nil) 如果缓存命中
  51. // 返回 (0, false, nil) 如果缓存未命中
  52. // 返回 (0, false, err) 如果发生错误
  53. GetWindowCost(ctx context.Context, accountID int64) (cost float64, hit bool, err error)
  54. // SetWindowCost 设置窗口费用缓存
  55. SetWindowCost(ctx context.Context, accountID int64, cost float64) error
  56. // GetWindowCostBatch 批量获取窗口费用缓存
  57. // 返回 map[accountID]cost,缓存未命中的账号不在 map 中
  58. GetWindowCostBatch(ctx context.Context, accountIDs []int64) (map[int64]float64, error)
  59. }