Skip to content

fix: stabilize session hash + add user-level session limit#634

Open
rikouu wants to merge 3 commits intoWei-Shaw:mainfrom
rikouu:fix/session-hash-and-user-limit
Open

fix: stabilize session hash + add user-level session limit#634
rikouu wants to merge 3 commits intoWei-Shaw:mainfrom
rikouu:fix/session-hash-and-user-limit

Conversation

@rikouu
Copy link

@rikouu rikouu commented Feb 25, 2026

Summary

This PR addresses two issues with session management and adds admin UI support:

1. Fix: Session Hash Stability

The GenerateSessionHash fallback previously used message content, causing the same user to be counted as multiple sessions across conversation turns. Now uses ClientIP+APIKeyID as a stable fallback.

2. Feature: User-Level Session Limit (max_sessions)

  • New max_sessions field on User model (DB column, default 0 = unlimited)
  • Enforced at account selection time via Redis (reuses existing session limit Lua scripts)
  • Redis key: session_limit:user:{userID}
  • Returns HTTP 429 with friendly error message when limit exceeded:

    "You have reached the maximum number of active sessions (N). Please close unused sessions with /exit or wait a few minutes before retrying."

3. Admin Panel UI for max_sessions

  • User create/edit modals: input field for max_sessions (0 = unlimited)
  • User list table: new column showing max_sessions (∞ for unlimited)
  • Full i18n support (en: "Max Sessions", zh: "最大会话数")
  • Backend handler/DTO/service wiring for CRUD operations

Compatibility

  • Default max_sessions = 0 (no limit) — fully backward compatible
  • No breaking API changes
  • Rebased on latest main (v0.1.86)

Bug fix:
- GenerateSessionHash fallback now uses ClientIP+APIKeyID instead of
  message content, preventing the same user from being counted as
  multiple sessions across conversation turns

New feature:
- Add user-level active session limit (max_sessions field on User)
- Redis key: session_limit:user:{userID} (reuses existing Lua scripts)
- checkAndRegisterUserSession called before account selection
- Default 0 = no limit (backward compatible)

修复活跃会话计算bug + 新增用户级会话数限制

Bug修复:
- GenerateSessionHash 的 fallback 改为使用 ClientIP+APIKeyID
  避免同一用户每轮对话被计为不同会话,虚增活跃会话数

新功能:
- User 新增 max_sessions 字段(默认0=不限制)
- Redis key: session_limit:user:{userID}
- 在账号选择前执行用户级会话检查
@rikouu rikouu force-pushed the fix/session-hash-and-user-limit branch from f096573 to 86338db Compare February 25, 2026 10:41
- Add max_sessions field to admin user create/edit forms and user list table
- Wire max_sessions through handler → service → DTO → frontend types
- Add i18n translations (en: 'Max Sessions', zh: '最大会话数')
- Return HTTP 429 with friendly message when user session limit exceeded
  (was: 503 with generic "No available accounts" error)
- Error message now guides users to close sessions or wait before retrying
@rikouu rikouu force-pushed the fix/session-hash-and-user-limit branch from 86338db to ac9e5af Compare February 25, 2026 10:48
Replace generic "no available accounts" with specific messages:
- "no schedulable accounts in pool" (all accounts disabled/rate-limited)
- "N accounts filtered (reasons)" (accounts exist but filtered out)
- "all accounts at capacity" (accounts valid but busy)
- "no matching accounts in pool" (legacy path, no match)

Also: pass error detail through in openai handler (was hidden as
"Service temporarily unavailable") and add missing UserSessionLimitError
check to openai handler for 429 response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rikouu
Copy link
Author

rikouu commented Feb 27, 2026

你好,想跟进一下这个 PR。session hash 的 fallback 用了消息内容来计算,导致同一个用户每轮对话都被算成不同会话,活跃会话数虚高,session limit 基本形同虚设。希望能抽空看一下,有任何需要调整的地方随时说 🙏

@Wei-Shaw
Copy link
Owner

你的请求主要来源是非claude code客户端吗?

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