fix(message): resolve Phase 5-6 audit findings

- Add missing version column to all message tables (migration + entities)
- Replace N+1 mark_all_read loop with single batch UPDATE query
- Fix NotificationList infinite re-render (extract queryFilter to stable ref)
- Fix NotificationPreferences dynamic import and remove unused Dayjs type
- Add Semaphore (max 8) to event listener for backpressure control
- Add /docs/openapi.json endpoint for API documentation
- Add permission check to unread_count handler
- Add version: Set(1) to all ActiveModel inserts
This commit is contained in:
iven
2026-04-11 14:16:45 +08:00
parent 97d3c9026b
commit f29f6d76ee
16 changed files with 180 additions and 38 deletions

View File

@@ -1,5 +1,7 @@
use axum::Router;
use axum::routing::{delete, get, put};
use std::sync::Arc;
use tokio::sync::Semaphore;
use uuid::Uuid;
use erp_core::error::AppResult;
@@ -60,16 +62,23 @@ impl MessageModule {
/// 启动后台事件监听任务,将工作流事件转化为消息通知。
///
/// 使用 Semaphore 限制最大并发数为 8防止事件突发时过度消耗资源。
/// 在 main.rs 中调用,因为需要 db 连接。
pub fn start_event_listener(db: sea_orm::DatabaseConnection, event_bus: EventBus) {
let mut rx = event_bus.subscribe();
let semaphore = Arc::new(Semaphore::new(8));
tokio::spawn(async move {
loop {
match rx.recv().await {
Ok(event) => {
let db = db.clone();
let event_bus = event_bus.clone();
let permit = semaphore.clone();
// 先获取许可,再 spawn 任务
tokio::spawn(async move {
let _permit = permit.acquire().await.unwrap();
if let Err(e) =
handle_workflow_event(&event, &db, &event_bus).await
{