Add Redis-backed chat queue

This commit is contained in:
2026-07-08 17:36:20 +08:00
parent db1d83631b
commit 23d5f42972
11 changed files with 349 additions and 7 deletions

View File

@@ -21,7 +21,13 @@ from app.schemas.chat import (
UpdateSessionTitleRequest,
)
from app.services.chat_service import ChatService
from app.services.chat_queue_service import chat_queue_manager, load_chat_queue_config
from app.services.chat_queue_runtime import (
cancel_chat_waiter,
release_chat_slot,
request_chat_slot,
wait_for_chat_slot,
)
from app.services.chat_queue_service import load_chat_queue_config
from app.services.chat_stream_service import ChatStreamService
router = APIRouter()
@@ -90,9 +96,10 @@ def stop(
async def _chat_stream(payload: ChatCompletionRequest, db: Session, current_user: User) -> AsyncIterator[str]:
config = load_chat_queue_config(db)
queue_request = chat_queue_manager.request_slot(config)
queue_lease = await request_chat_slot(config)
queue_request = queue_lease.request
acquired = queue_request.status == "acquired"
queued_token = queue_request.token
should_cancel_waiter = queue_request.status == "queued"
if queue_request.status == "rejected":
yield _sse_event(
@@ -112,12 +119,27 @@ async def _chat_stream(payload: ChatCompletionRequest, db: Session, current_user
activeCount=queue_request.active_count,
waitingCount=queue_request.waiting_count,
)
queue_request = await asyncio.to_thread(chat_queue_manager.wait_for_slot, queued_token, config)
queue_lease = await wait_for_chat_slot(queue_lease, config)
queue_request = queue_lease.request
acquired = queue_request.status == "acquired"
should_cancel_waiter = queue_request.status == "queued"
if queue_request.status == "rejected":
yield _sse_event(
"error",
message="当前请求过多,请稍后再试。",
activeCount=queue_request.active_count,
waitingCount=queue_request.waiting_count,
)
yield _sse_done()
return
if queue_request.status == "timeout":
yield _sse_event("error", message="排队等待超时,请稍后再试。")
yield _sse_done()
return
if queue_request.status == "canceled":
yield _sse_event("error", message="排队请求已取消,请稍后再试。")
yield _sse_done()
return
try:
yield _sse_event(
@@ -136,9 +158,9 @@ async def _chat_stream(payload: ChatCompletionRequest, db: Session, current_user
yield _sse_event("error", message="AI 回复生成失败,请稍后再试。")
finally:
if acquired:
chat_queue_manager.release_slot()
elif queued_token is not None:
chat_queue_manager.cancel_waiter(queued_token)
await release_chat_slot(queue_lease)
elif should_cancel_waiter:
await cancel_chat_waiter(queue_lease)
yield _sse_done()