use anyhow::Result;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct ExecutionPlan {
pub phases: Vec<ExecutionPhase>,
pub env_vars: HashMap<String, serde_yaml::Value>,
pub flow_vars: HashMap<String, serde_yaml::Value>,
pub metadata: PlanMetadata,
}
#[derive(Debug, Clone)]
pub struct ExecutionPhase {
pub id: String,
pub name: String,
pub execution_mode: PhaseExecutionMode,
pub nodes: Vec<ExecutionNode>,
pub condition: Option<String>,
}
#[derive(Debug, Clone)]
pub enum PhaseExecutionMode {
Sequential,
Parallel,
Conditional { condition: String },
}
#[derive(Debug, Clone)]
pub struct ExecutionNode {
pub id: String,
pub name: String,
pub node_type: NodeType,
pub action_spec: ActionSpec,
pub dependencies: Vec<String>,
pub condition: Option<String>,
pub priority: u32,
pub retry_config: Option<RetryConfig>,
pub timeout_config: Option<TimeoutConfig>,
}
#[derive(Debug, Clone)]
pub enum NodeType {
Action,
Condition,
Branch,
Loop,
Subprocess,
}
#[derive(Debug, Clone)]
pub struct ActionSpec {
pub action_type: String,
pub parameters: HashMap<String, serde_yaml::Value>,
pub outputs: HashMap<String, serde_yaml::Value>,
}
#[derive(Debug, Clone)]
pub struct RetryConfig {
pub max_retries: u32,
pub delay: u64,
pub strategy: RetryStrategy,
}
#[derive(Debug, Clone)]
pub enum RetryStrategy {
Fixed,
Exponential { multiplier: f64 },
Linear { increment: u64 },
}
#[derive(Debug, Clone)]
pub struct TimeoutConfig {
pub duration: u64,
pub on_timeout: Option<String>,
}
#[derive(Debug, Clone)]
pub struct PlanMetadata {
pub plan_id: String,
pub created_at: std::time::SystemTime,
pub workflow_name: String,
pub workflow_version: String,
pub total_nodes: usize,
pub total_phases: usize,
}
pub trait Executor {
type Input;
type Output;
type Error;
fn execute(
&mut self,
input: Self::Input,
) -> impl std::future::Future<Output = Result<Self::Output, Self::Error>> + Send;
fn status(&self) -> ExecutorStatus;
fn stop(
&mut self,
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send;
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExecutorStatus {
Idle,
Running,
Stopped,
Error(String),
}
pub trait ConfigParser<T> {
type Output;
type Error;
fn parse(&self, config: T) -> Result<Self::Output, Self::Error>;
}
pub trait FlowPlanner {
type Input;
type Output;
type Error;
fn create_execution_plan(
&self,
input: Self::Input,
) -> Result<Self::Output, Self::Error>;
fn optimize_plan(
&self,
plan: Self::Output,
) -> Result<Self::Output, Self::Error>;
}
pub trait ExpressionEvaluator {
type Value;
type Error;
fn evaluate(&self, expression: &str) -> Result<Self::Value, Self::Error>;
fn evaluate_condition(&self, condition: &str) -> Result<bool, Self::Error>;
fn set_variable(&mut self, name: String, value: Self::Value);
fn get_variable(&self, name: &str) -> Option<Self::Value>;
}
impl ExecutionPlan {
pub fn new(
workflow_name: String,
workflow_version: String,
env_vars: HashMap<String, serde_yaml::Value>,
flow_vars: HashMap<String, serde_yaml::Value>,
) -> Self {
let metadata = PlanMetadata {
plan_id: uuid::Uuid::new_v4().to_string(),
created_at: std::time::SystemTime::now(),
workflow_name,
workflow_version,
total_nodes: 0,
total_phases: 0,
};
Self {
phases: Vec::new(),
env_vars,
flow_vars,
metadata,
}
}
pub fn add_phase(&mut self, phase: ExecutionPhase) {
self.metadata.total_nodes += phase.nodes.len();
self.phases.push(phase);
self.metadata.total_phases = self.phases.len();
}
pub fn estimated_duration(&self) -> std::time::Duration {
let total_nodes = self.metadata.total_nodes;
std::time::Duration::from_millis((total_nodes * 100) as u64)
}
pub fn validate(&self) -> Result<(), String> {
if self.phases.is_empty() {
return Err("执行计划不能为空".to_string());
}
for phase in &self.phases {
if phase.nodes.is_empty() {
return Err(format!("阶段 {} 不能为空", phase.name));
}
}
Ok(())
}
}
impl ExecutionNode {
pub fn new(id: String, name: String, action_spec: ActionSpec) -> Self {
Self {
id,
name,
node_type: NodeType::Action,
action_spec,
dependencies: Vec::new(),
condition: None,
priority: 100,
retry_config: None,
timeout_config: None,
}
}
pub fn add_dependency(mut self, dependency: String) -> Self {
self.dependencies.push(dependency);
self
}
pub fn with_condition(mut self, condition: String) -> Self {
self.condition = Some(condition);
self
}
pub fn with_priority(mut self, priority: u32) -> Self {
self.priority = priority;
self
}
pub fn with_retry(mut self, retry_config: RetryConfig) -> Self {
self.retry_config = Some(retry_config);
self
}
pub fn with_timeout(mut self, timeout_config: TimeoutConfig) -> Self {
self.timeout_config = Some(timeout_config);
self
}
}