feat(plugin): P1-P4 审计修复 — 第二批 (运行时监控 + 通知引擎 + 编号reset)
2.1 运行时监控:
- LoadedPlugin 新增 RuntimeMetrics (调用次数/错误/响应时间/燃料消耗)
- execute_wasm 自动采集每次调用的耗时和状态
- GET /admin/plugins/{id}/metrics 端点
2.2 通知规则引擎:
- notification.rs: 订阅 plugin.trigger.* 事件
- 触发时自动给管理员发送消息通知
- emit_trigger_events 增加 manifest_id 到 payload
2.3 编号 reset_rule:
- 替换 PostgreSQL SEQUENCE 为表行 + pg_advisory_xact_lock
- 支持 daily/monthly/yearly/never 重置周期
- 每个周期独立计数,切换时自动重置为 1
This commit is contained in:
@@ -78,6 +78,19 @@ pub struct LoadedPlugin {
|
||||
pub linker: Linker<HostState>,
|
||||
pub status: RwLock<PluginStatus>,
|
||||
pub event_handles: RwLock<Vec<tokio::task::JoinHandle<()>>>,
|
||||
pub metrics: Arc<RwLock<RuntimeMetrics>>,
|
||||
}
|
||||
|
||||
/// 插件运行时指标
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub struct RuntimeMetrics {
|
||||
pub total_invocations: u64,
|
||||
pub error_count: u64,
|
||||
pub total_response_ms: f64,
|
||||
pub fuel_consumed_total: u64,
|
||||
pub memory_peak_bytes: u64,
|
||||
pub last_error: Option<String>,
|
||||
pub last_invocation_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
}
|
||||
|
||||
/// WASM 执行上下文 — 传递真实的租户和用户信息
|
||||
@@ -146,6 +159,7 @@ impl PluginEngine {
|
||||
linker,
|
||||
status: RwLock::new(PluginStatus::Loaded),
|
||||
event_handles: RwLock::new(vec![]),
|
||||
metrics: Arc::new(RwLock::new(RuntimeMetrics::default())),
|
||||
});
|
||||
|
||||
self.plugins.insert(plugin_id.to_string(), loaded);
|
||||
@@ -391,6 +405,13 @@ impl PluginEngine {
|
||||
.map(|entry| entry.manifest.clone())
|
||||
}
|
||||
|
||||
/// 获取插件运行时指标
|
||||
pub async fn get_metrics(&self, plugin_id: &str) -> PluginResult<RuntimeMetrics> {
|
||||
let loaded = self.get_loaded(plugin_id)?;
|
||||
let metrics = loaded.metrics.read().await;
|
||||
Ok(metrics.clone())
|
||||
}
|
||||
|
||||
/// 检查插件是否正在运行
|
||||
pub async fn is_running(&self, plugin_id: &str) -> bool {
|
||||
if let Some(loaded) = self.plugins.get(plugin_id) {
|
||||
@@ -521,6 +542,7 @@ impl PluginEngine {
|
||||
|
||||
let timeout_secs = self.config.execution_timeout_secs;
|
||||
let pid_owned = plugin_id.to_owned();
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
// spawn_blocking 闭包执行 WASM,正常完成时收集 pending_ops
|
||||
let (result, pending_ops): (PluginResult<R>, Vec<PendingOp>) =
|
||||
@@ -552,6 +574,19 @@ impl PluginEngine {
|
||||
})?
|
||||
.map_err(|e| PluginError::ExecutionError(e.to_string()))?;
|
||||
|
||||
// 更新运行时指标
|
||||
let elapsed_ms = start.elapsed().as_millis() as f64;
|
||||
{
|
||||
let mut metrics = loaded.metrics.write().await;
|
||||
metrics.total_invocations += 1;
|
||||
metrics.total_response_ms += elapsed_ms;
|
||||
metrics.last_invocation_at = Some(chrono::Utc::now());
|
||||
if result.is_err() {
|
||||
metrics.error_count += 1;
|
||||
metrics.last_error = result.as_ref().err().map(|e| e.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新写操作到数据库
|
||||
Self::flush_ops(
|
||||
&self.db,
|
||||
|
||||
Reference in New Issue
Block a user