feat: add queue status endpoint for upload page

GET /api/v2/system/queue/status returns counts of documents
by processing_status (waiting/processing) from leaudit_documents,
plus processing document IDs for the frontend progress display.
This commit is contained in:
wren
2026-04-30 12:32:37 +08:00
parent 969c3aaf35
commit 9e1b7a6de7
@@ -3,7 +3,10 @@
from typing import Any from typing import Any
from fastapi import File, Form, Query, UploadFile from fastapi import File, Form, Query, UploadFile
from pydantic import BaseModel, Field
from sqlalchemy import text
from fastapi_common.fastapi_common_sqlalchemy.database import GetAsyncSession
from fastapi_common.fastapi_common_web.controller import BaseController from fastapi_common.fastapi_common_web.controller import BaseController
from fastapi_common.fastapi_common_web.domain.responses import Result from fastapi_common.fastapi_common_web.domain.responses import Result
@@ -12,6 +15,13 @@ from fastapi_modules.fastapi_leaudit.services import IDocumentService
from fastapi_modules.fastapi_leaudit.services.impl.documentServiceImpl import DocumentServiceImpl from fastapi_modules.fastapi_leaudit.services.impl.documentServiceImpl import DocumentServiceImpl
class QueueStatusVO(BaseModel):
success: bool = Field(True)
timestamp: str = Field("")
queue: dict[str, int] = Field(default_factory=lambda: {"pending_tasks": 0, "processing_tasks": 0, "available_slots": 4, "max_concurrent": 4})
documents: dict[str, object] = Field(default_factory=lambda: {"waiting": 0, "processing": 0, "processing_ids": []})
class DocumentController(BaseController): class DocumentController(BaseController):
"""文档控制器。""" """文档控制器。"""
@@ -84,3 +94,69 @@ class DocumentController(BaseController):
idList = [int(x.strip()) for x in ids.split(",") if x.strip().isdigit()] idList = [int(x.strip()) for x in ids.split(",") if x.strip().isdigit()]
Data = await self.DocumentService.ListDocumentTypes(Ids=idList) Data = await self.DocumentService.ListDocumentTypes(Ids=idList)
return Result.success(data=Data) return Result.success(data=Data)
@self.router.get("/v2/system/queue/status", response_model=Result[QueueStatusVO])
async def GetQueueStatus():
"""获取文档处理队列状态。"""
from datetime import datetime
async with GetAsyncSession() as Session:
statusRows = (
await Session.execute(
text(
"""
SELECT processing_status, COUNT(*) AS cnt
FROM leaudit_documents
WHERE deleted_at IS NULL AND is_latest_version = true
GROUP BY processing_status
"""
)
)
).mappings().all()
waiting = 0
processing = 0
for row in statusRows:
s = str(row["processing_status"] or "")
c = int(row["cnt"] or 0)
if s == "waiting":
waiting = c
elif s in ("processing", "running"):
processing += c
processingIdsRows: list[int] = []
if processing > 0:
async with GetAsyncSession() as Session:
idRows = (
await Session.execute(
text(
"""
SELECT id FROM leaudit_documents
WHERE deleted_at IS NULL
AND is_latest_version = true
AND processing_status IN ('processing', 'running')
ORDER BY updated_at DESC
LIMIT 50
"""
)
)
).fetchall()
processingIdsRows = [int(r[0]) for r in idRows]
return Result.success(
data=QueueStatusVO(
success=True,
timestamp=datetime.now().isoformat(),
queue={
"pending_tasks": waiting,
"processing_tasks": processing,
"available_slots": max(0, 4 - processing),
"max_concurrent": 4,
},
documents={
"waiting": waiting,
"processing": processing,
"processing_ids": processingIdsRows,
},
)
)