feat(health): P0 平台基座回顾 — 7项上线前必修
P0-1: 危急值告警消费者 — health_data.critical_alert 事件推送给责任医护 P0-2: 危急值阈值可配置化 — 硬编码改为数据库配置(critical_value_threshold表),支持科室/年龄差异化 P0-3: daily_monitoring合并后告警验证 — update_vital_signs也触发危急值检测 P0-4: 随访逾期通知+幂等保护 — 只通知本次新标记的逾期任务,避免重复 P0-5: 知情同意记录(consent) — 新增实体/迁移/Service/Handler,PIPL合规 P0-6: 审计日志补全 — 患者更新记录前后值(过敏史/病史/状态变更) P0-7: EventBus持久化增强 — 两阶段提交(pending→published)+启动时outbox relay恢复
This commit is contained in:
@@ -69,33 +69,47 @@ impl EventBus {
|
||||
Self { sender }
|
||||
}
|
||||
|
||||
/// 发布事件:先持久化到 domain_events 表,再内存广播。
|
||||
/// 发布事件:先持久化到 domain_events 表(pending 状态),再内存广播,
|
||||
/// 最后更新为 published。
|
||||
///
|
||||
/// 持久化失败时仅记录 warning,仍然广播(best-effort)。
|
||||
/// 两阶段提交保证:即使广播后服务崩溃,事件仍为 pending 状态,
|
||||
/// 重启后 outbox relay 会重新广播。
|
||||
pub async fn publish(&self, event: DomainEvent, db: &sea_orm::DatabaseConnection) {
|
||||
// 持久化到 domain_events 表
|
||||
// 1. 持久化为 pending 状态
|
||||
let event_id = event.id;
|
||||
let model = domain_event::ActiveModel {
|
||||
id: Set(event.id),
|
||||
tenant_id: Set(event.tenant_id),
|
||||
event_type: Set(event.event_type.clone()),
|
||||
payload: Set(Some(event.payload.clone())),
|
||||
correlation_id: Set(Some(event.correlation_id)),
|
||||
status: Set("published".to_string()),
|
||||
status: Set("pending".to_string()),
|
||||
attempts: Set(0),
|
||||
last_error: Set(None),
|
||||
created_at: Set(event.timestamp),
|
||||
published_at: Set(Some(Utc::now())),
|
||||
published_at: Set(None),
|
||||
};
|
||||
|
||||
match model.insert(db).await {
|
||||
Ok(_) => {}
|
||||
let saved = match model.insert(db).await {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
tracing::warn!(event_id = %event.id, error = %e, "领域事件持久化失败");
|
||||
tracing::warn!(event_id = %event_id, error = %e, "领域事件持久化失败");
|
||||
// 持久化失败仍然广播(best-effort)
|
||||
self.broadcast(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 内存广播
|
||||
// 2. 内存广播
|
||||
self.broadcast(event);
|
||||
|
||||
// 3. 更新为 published
|
||||
let mut active: domain_event::ActiveModel = saved.into();
|
||||
active.status = Set("published".to_string());
|
||||
active.published_at = Set(Some(Utc::now()));
|
||||
if let Err(e) = active.update(db).await {
|
||||
tracing::warn!(event_id = %event_id, error = %e, "领域事件状态更新为 published 失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// 仅内存广播(不持久化,用于内部测试等场景)。
|
||||
|
||||
Reference in New Issue
Block a user