feat(server): outbox relay 改为 LISTEN/NOTIFY + 30s 兜底轮询
- EventBus::publish() 持久化后执行 NOTIFY outbox_channel - outbox relay 使用 sqlx::PgListener 监听 + tokio::select! 竞争 - 30s 兜底轮询防止 NOTIFY 丢失,断线自动重连 - 轮询间隔从 5s 提升到 30s,事件延迟降至 <100ms
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use chrono::Utc;
|
||||
use sea_orm::{ActiveModelTrait, Set};
|
||||
use sea_orm::{ActiveModelTrait, ConnectionTrait, Set};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::{broadcast, mpsc};
|
||||
use tracing::{error, info};
|
||||
@@ -70,7 +70,7 @@ impl EventBus {
|
||||
}
|
||||
|
||||
/// 发布事件:先持久化到 domain_events 表(pending 状态),再内存广播,
|
||||
/// 最后更新为 published。
|
||||
/// 最后更新为 published 并 NOTIFY outbox relay。
|
||||
///
|
||||
/// 两阶段提交保证:即使广播后服务崩溃,事件仍为 pending 状态,
|
||||
/// 重启后 outbox relay 会重新广播。
|
||||
@@ -110,6 +110,15 @@ impl EventBus {
|
||||
if let Err(e) = active.update(db).await {
|
||||
tracing::warn!(event_id = %event_id, error = %e, "领域事件状态更新为 published 失败");
|
||||
}
|
||||
|
||||
// 4. NOTIFY outbox relay(通知 outbox relay 有新事件到达)
|
||||
let notify_sql = sea_orm::Statement::from_string(
|
||||
sea_orm::DatabaseBackend::Postgres,
|
||||
format!("NOTIFY outbox_channel, '{}'", event_id),
|
||||
);
|
||||
if let Err(e) = db.execute(notify_sql).await {
|
||||
tracing::debug!(event_id = %event_id, error = %e, "NOTIFY outbox_channel 失败(非致命)");
|
||||
}
|
||||
}
|
||||
|
||||
/// 仅内存广播(不持久化,用于内部测试等场景)。
|
||||
|
||||
Reference in New Issue
Block a user