feat(core): 事件归档 + 消费者幂等性 — 迁移 084/085 + 清理任务
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- 迁移 084: domain_events_archive 归档表 + cleanup_old_published_events()
- 迁移 085: processed_events 去重表 + cleanup_old_processed_events()
- erp-core: is_event_processed() / mark_event_processed() 幂等性辅助
- erp-server: tasks::start_event_cleanup() 每 24h 归档 >90 天事件
This commit is contained in:
iven
2026-04-27 18:12:43 +08:00
parent 97bb592688
commit 3197dde33c
8 changed files with 279 additions and 1 deletions

View File

@@ -4,6 +4,7 @@ mod handlers;
mod middleware;
mod outbox;
mod state;
mod tasks;
/// OpenAPI 规范定义 — 通过 utoipa derive 合并各模块 schema。
#[derive(OpenApi)]
@@ -410,6 +411,9 @@ async fn main() -> anyhow::Result<()> {
outbox::start_outbox_relay(db.clone(), event_bus.clone(), config.database.url.clone());
tracing::info!("Outbox relay started");
// Start event cleanup (archive old published events + purge processed_events)
tasks::start_event_cleanup(db.clone());
// Start timeout checker (scan overdue tasks every 60s)
erp_workflow::WorkflowModule::start_timeout_checker(db.clone(), event_bus.clone());
tracing::info!("Timeout checker started");

View File

@@ -0,0 +1,53 @@
use std::time::Duration;
/// 启动事件清理后台任务。
///
/// 每日执行一次:
/// - 调用 `cleanup_old_published_events()` 归档 >90 天的已发布事件
/// - 调用 `cleanup_old_processed_events()` 清理 >7 天的去重记录
pub fn start_event_cleanup(db: sea_orm::DatabaseConnection) {
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(86400));
loop {
interval.tick().await;
if let Err(e) = run_cleanup(&db).await {
tracing::warn!(error = %e, "事件清理任务执行失败");
}
}
});
tracing::info!("事件清理任务已启动(每 24 小时执行一次)");
}
async fn run_cleanup(db: &sea_orm::DatabaseConnection) -> Result<(), sea_orm::DbErr> {
use sea_orm::ConnectionTrait;
// 归档 >90 天的已发布事件
match db
.execute_unprepared("SELECT cleanup_old_published_events(90, 1000)")
.await
{
Ok(result) => {
tracing::info!(
rows_affected = result.rows_affected(),
"已发布事件归档完成"
);
}
Err(e) => tracing::warn!(error = %e, "已发布事件归档失败"),
}
// 清理 >7 天的去重记录
match db
.execute_unprepared("SELECT cleanup_old_processed_events(7, 1000)")
.await
{
Ok(result) => {
tracing::info!(
rows_affected = result.rows_affected(),
"去重记录清理完成"
);
}
Err(e) => tracing::warn!(error = %e, "去重记录清理失败"),
}
Ok(())
}