Skip to content

Commit 703a7ae

Browse files
committed
fix(guest_session_pool): 防止并发创建重复匿名会话
- 在 acquire 方法中添加容量锁,避免多个并发请求同时创建新会话 - 添加 README 文档说明认证 Token 与匿名会话的优先级关系
1 parent a4e4b85 commit 703a7ae

2 files changed

Lines changed: 50 additions & 21 deletions

File tree

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,33 @@ docker compose -f deploy/docker-compose.yml up -d --build
6262

6363
完整配置请看 [.env.example](.env.example)
6464

65+
## Token 与匿名会话优先级
66+
67+
系统同时支持**认证 Token 池****匿名会话池**,处理优先级如下:
68+
69+
```
70+
认证 Token 池(优先)
71+
72+
(全部失效/排除)
73+
74+
匿名会话池(备选)
75+
```
76+
77+
### 优先级说明
78+
79+
| 优先级 | 来源 | 触发条件 |
80+
|:---:|------|----------|
81+
| 1️⃣ | 认证 Token 池 | 数据库中存在有效 Token 时,优先使用 |
82+
| 2️⃣ | 匿名会话池 | 认证 Token 全部失效或被排除完,且 `ANONYMOUS_MODE=true` |
83+
84+
### 相关配置
85+
86+
- `ANONYMOUS_MODE`:是否启用匿名模式,默认为 `true`
87+
- `GUEST_POOL_SIZE`:匿名会话池大小,默认 `3`
88+
- `GUEST_SESSION_MAX_AGE`:匿名会话最大存活时间,默认 `480` 分钟
89+
90+
> **注意**:即使认证 Token 池和匿名会话池同时存在,系统也会**始终优先使用认证 Token**,只有当认证 Token 全部不可用时,才会使用匿名会话作为备选方案。
91+
6592
## 管理后台
6693

6794
管理后台统一入口:

app/utils/guest_session_pool.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -404,28 +404,30 @@ async def acquire(
404404
"""按最小忙碌度获取一个可用匿名会话。"""
405405
excluded = exclude_user_ids or set()
406406

407-
while True:
408-
candidates = self._list_valid_sessions(exclude_user_ids=excluded)
409-
if candidates:
410-
session = min(
411-
candidates,
412-
key=lambda item: (item.active_requests, item.created_at),
413-
)
414-
with self._lock:
415-
current = self._sessions.get(session.user_id)
416-
if current and current.valid and current.user_id not in excluded:
417-
current.active_requests += 1
418-
return current
419-
420-
new_session = await self._create_session()
421-
if new_session.user_id in excluded:
422-
await self._delete_all_chats(new_session)
423-
continue
407+
# 使用容量锁防止并发创建重复会话
408+
async with self._capacity_lock:
409+
while True:
410+
candidates = self._list_valid_sessions(exclude_user_ids=excluded)
411+
if candidates:
412+
session = min(
413+
candidates,
414+
key=lambda item: (item.active_requests, item.created_at),
415+
)
416+
with self._lock:
417+
current = self._sessions.get(session.user_id)
418+
if current and current.valid and current.user_id not in excluded:
419+
current.active_requests += 1
420+
return current
421+
422+
new_session = await self._create_session()
423+
if new_session.user_id in excluded:
424+
await self._delete_all_chats(new_session)
425+
continue
424426

425-
with self._lock:
426-
new_session.active_requests = 1
427-
self._sessions[new_session.user_id] = new_session
428-
return new_session
427+
with self._lock:
428+
new_session.active_requests = 1
429+
self._sessions[new_session.user_id] = new_session
430+
return new_session
429431

430432
def release(self, user_id: str):
431433
"""释放一个匿名会话占用。"""

0 commit comments

Comments
 (0)