From 5ce8b7290060e70cc85dfb4919fe662de6c07f14 Mon Sep 17 00:00:00 2001 From: Catty Steve <4795515+Catty2014@user.noreply.gitee.com> Date: Fri, 24 Apr 2026 23:01:40 +0800 Subject: [PATCH] refactor(notify): extract types to separate module and redesign NotificationRule - Move NotifyEvent, NotifyPluginMap, and related types to notify/types.rs - Introduce NotificationRule struct replacing NotificationMethod fields - Add NotificationRulesMap for priority-based notification configuration - Comment out main event loop and add todo!() placeholders for WIP --- workshop-baker/src/finalize/config.rs | 12 -- workshop-baker/src/notify.rs | 164 +++++++++----------------- workshop-baker/src/notify/types.rs | 96 +++++++++++++++ 3 files changed, 151 insertions(+), 121 deletions(-) create mode 100644 workshop-baker/src/notify/types.rs diff --git a/workshop-baker/src/finalize/config.rs b/workshop-baker/src/finalize/config.rs index 9456a29..6ef8746 100644 --- a/workshop-baker/src/finalize/config.rs +++ b/workshop-baker/src/finalize/config.rs @@ -99,18 +99,6 @@ pub struct PluginRuntimeConfig { /// Notification method configuration #[derive(Debug, Deserialize, Serialize, Clone)] pub struct NotificationMethod { - /// Whether notification failure should not trigger next priority group - #[serde(default)] - pub fallible: bool, - - /// Number of retries on failure (0 = no retry, -1 = infinite retries) - #[serde(default)] - pub retry: i8, - - /// Timeout for notification execution in milliseconds (0 = no timeout) - #[serde(default)] - pub timeout_ms: u64, - /// Template definition #[serde(default)] pub template: NotificationTemplate, diff --git a/workshop-baker/src/notify.rs b/workshop-baker/src/notify.rs index 8d5d9eb..75bce82 100644 --- a/workshop-baker/src/notify.rs +++ b/workshop-baker/src/notify.rs @@ -1,23 +1,24 @@ use crate::constant::FINALIZE_STANDALONE_PLUGIN_PATH; use crate::finalize::FinalizeConfig; -use crate::finalize::NotificationConfig; use crate::finalize::parse; use crate::finalize::plugin; -use crate::finalize::plugin::FinalizePlugin; use crate::finalize::plugin::fetch; -use crate::types::buildstatus::StagePhase; -use crate::types::buildstatus::StageResult; +use crate::notify::types::BundledNotifyEvent; +use crate::notify::types::NOTIFY_TEMPORARY_DELAY_FACTOR; +use crate::notify::types::NOTIFY_TEMPORARY_DELAY_TIME; +use crate::notify::types::NOTIFY_TEMPORARY_MAX_TIME; +use crate::notify::types::NotificationRulesMap; +use crate::notify::types::NotifyEvent; +use crate::notify::types::NotifyEventReceiver; +use crate::notify::types::NotifyEventSender; +use crate::notify::types::NotifyPluginMap; use crate::{EventSender, ExecutionContext}; -use chrono::{DateTime, Utc}; -use serde::Serialize; -use std::collections::HashMap; use std::collections::HashSet; -use std::hash::Hash; use std::path::Path; use std::path::PathBuf; -use uuid::Uuid; mod error; +mod types; use error::NotifyError; fn validate(finalize: &FinalizeConfig) -> anyhow::Result<()> { @@ -31,8 +32,6 @@ fn validate(finalize: &FinalizeConfig) -> anyhow::Result<()> { Ok(()) } -pub type NotifyPluginMap = HashMap; - fn extract_plugin(finalize: &FinalizeConfig) -> HashSet { finalize .notification @@ -43,60 +42,6 @@ fn extract_plugin(finalize: &FinalizeConfig) -> HashSet { .collect() } -#[derive(Debug, Clone, Serialize)] -pub struct NotifyEvent { - id: Uuid, - stage: StagePhase, - substage: String, - result: StageResult, - not_before: DateTime, - priority: u32, - effective_priority: u32, - lives: u32, - max_lives: u32, - target: HashSet, // Target audience -} - -impl Hash for NotifyEvent { - fn hash(&self, state: &mut H) { - self.id.hash(state); - } -} - -impl PartialEq for NotifyEvent { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl Eq for NotifyEvent {} - -impl PartialOrd for NotifyEvent { - fn partial_cmp(&self, other: &Self) -> Option { - Some( - self.effective_priority - .cmp(&other.effective_priority) - .then(self.not_before.cmp(&other.not_before)) - .reverse(), - ) - } -} - -impl Ord for NotifyEvent { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.partial_cmp(other).unwrap() - } -} - -type BundledNotifyEvent = Vec; -type NotifyEventReceiver = tokio::sync::mpsc::Receiver; -pub type NotifyEventSender = tokio::sync::mpsc::Sender; - -const NOTIFY_NOTREADY_DELAY: std::time::Duration = std::time::Duration::from_secs(5); -const NOTIFY_TEMPORARY_DELAY_FACTOR: f64 = 2.0; -const NOTIFY_TEMPORARY_DELAY_TIME: f64 = 5.0; -const NOTIFY_TEMPORARY_MAX_TIME: f64 = f64::MAX; - pub async fn notify( finalize_path: &Path, ctx: &mut ExecutionContext, @@ -124,53 +69,54 @@ pub async fn notify( } let notify_plugins = plugin::register(finalize.plugin, Some(&plugin_list))?; - loop { - tokio::select! { - Some(events) = notifyevent_rx.recv() => { - match notify_handler(¬ify_plugins, &finalize.notification, &events){ - Ok(_) => {}, // Notification succeeded / failed with fallible - Err(e) => { - log::debug!("Failed to send notification: {:?}", e); - match e { - NotifyError::PluginNotAvailable(_) => { - // Should keep lives, add static delay and give less priority - for mut event in events { - event.not_before = Utc::now() + NOTIFY_NOTREADY_DELAY; - event.effective_priority = event.effective_priority.saturating_add(1); - notifyevent_tx.send(event).await?; - } - }, - NotifyError::TemporaryError(_) => { - // Should cost 1 life, add dynamic (exponential) delay - for mut event in events { - event.lives -= 1; - event.not_before = Utc::now() + notify_delay(&event); - notifyevent_tx.send(event).await?; - } - }, - NotifyError::PermanentError(_) => { - // Unexpected! - // Should be dropped - log::error!("None of the configured notification plugins works."); - log::error!("Message will be dropped."); - // TODO: Send audit/metric information - } - error => { - // Unexpected! - log::error!("Internal error: notify_handler returned unexpected error: {:?}", error); - } - }; - } - }; - } - } - } + // loop { + // tokio::select! { + // Some(events) = notifyevent_rx.recv() => { + // match notify_handler(¬ify_plugins, &finalize.notification, &events){ + // Ok(_) => {}, // Notification succeeded / failed with fallible + // Err(e) => { + // log::debug!("Failed to send notification: {:?}", e); + // match e { + // NotifyError::PluginNotAvailable(_) => { + // // Should keep lives, add static delay and give less priority + // for mut event in events { + // event.not_before = Utc::now() + NOTIFY_NOTREADY_DELAY; + // event.effective_priority = event.effective_priority.saturating_add(1); + // notifyevent_tx.send(event).await?; + // } + // }, + // NotifyError::TemporaryError(_) => { + // // Should cost 1 life, add dynamic (exponential) delay + // for mut event in events { + // event.lives -= 1; + // event.not_before = Utc::now() + notify_delay(&event); + // notifyevent_tx.send(event).await?; + // } + // }, + // NotifyError::PermanentError(_) => { + // // Unexpected! + // // Should be dropped + // log::error!("None of the configured notification plugins works."); + // log::error!("Message will be dropped."); + // // TODO: Send audit/metric information + // } + // error => { + // // Unexpected! + // log::error!("Internal error: notify_handler returned unexpected error: {:?}", error); + // } + // }; + // } + // }; + // } + // } + // } + todo!(); } -fn notify_handler( +fn notification_handler( plugins: &NotifyPluginMap, - config: &NotificationConfig, - event: &Vec, + config: &NotificationRulesMap, + event: &BundledNotifyEvent, ) -> Result<(), NotifyError> { todo!(); } diff --git a/workshop-baker/src/notify/types.rs b/workshop-baker/src/notify/types.rs new file mode 100644 index 0000000..b852dfb --- /dev/null +++ b/workshop-baker/src/notify/types.rs @@ -0,0 +1,96 @@ +use std::collections::HashMap; +use std::collections::HashSet; +use std::time::Duration; +use crate::finalize::plugin::FinalizePlugin; +use crate::types::buildstatus::StagePhase; +use crate::types::buildstatus::StageResult; +use chrono::{DateTime, Utc}; +use serde::Serialize; +use std::hash::Hash; +use uuid::Uuid; + +use crate::finalize::NotificationTemplate; +use crate::finalize::config::Trigger; +/// Final runtime configuration for notification, restored and flattened from yaml +pub struct NotificationRule{ + pub enabled: bool, + + pub trigger: Vec, + + pub template: NotificationTemplate, + + /// Whether notification failure should not trigger next priority group + pub fallible: bool, + + /// Maximum number of attempts + pub max_lives: u32, + + /// Timeout for notification execution + pub timeout: Duration, + + /// Plugin-specific configuration + pub config: serde_yaml::Value, + + /// Factor of exponential backoff for retry delay + // Not provided for external use + pub retry_backoff: f64, +} + +pub type Priority = u32; +pub type Method = String; +pub type NotificationRulesMap = HashMap>>; +pub type BundledNotifyEvent = Vec; +pub type NotifyEventReceiver = tokio::sync::mpsc::Receiver; +pub type NotifyEventSender = tokio::sync::mpsc::Sender; +pub type NotifyPluginMap = HashMap; + +#[derive(Debug, Clone, Serialize)] +pub struct NotifyEvent { + pub id: Uuid, + pub stage: StagePhase, + pub substage: String, + pub result: StageResult, + pub not_before: DateTime, + pub priority: u32, + pub effective_priority: u32, + pub lives: u32, + pub max_lives: u32, + pub target: HashSet, // Target audience +} + +impl Hash for NotifyEvent { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl PartialEq for NotifyEvent { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +impl Eq for NotifyEvent {} + +impl PartialOrd for NotifyEvent { + fn partial_cmp(&self, other: &Self) -> Option { + Some( + self.effective_priority + .cmp(&other.effective_priority) + .then(self.not_before.cmp(&other.not_before)) + .reverse(), + ) + } +} + +impl Ord for NotifyEvent { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } +} + + +pub const NOTIFY_NOTREADY_DELAY: std::time::Duration = std::time::Duration::from_secs(5); +pub const NOTIFY_TEMPORARY_DELAY_FACTOR: f64 = 2.0; +pub const NOTIFY_TEMPORARY_DELAY_TIME: f64 = 5.0; +pub const NOTIFY_TEMPORARY_MAX_TIME: f64 = f64::MAX;