283 lines
9.7 KiB
Rust
283 lines
9.7 KiB
Rust
//! Basic workflow example demonstrating orchestrator usage
|
|
|
|
use orchestrator::{
|
|
interface::LocalInterface,
|
|
orchestrator::Orchestrator,
|
|
OrchestratedFlow, OrchestratedFlowStep, FlowStatus,
|
|
};
|
|
use std::sync::Arc;
|
|
use std::collections::HashMap;
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// Initialize logging
|
|
tracing_subscriber::fmt().init();
|
|
|
|
// Create executor
|
|
let executor = Arc::new(LocalInterface::new());
|
|
|
|
// Create orchestrator
|
|
let orchestrator = Orchestrator::new(executor);
|
|
|
|
println!("🚀 Starting basic workflow example");
|
|
|
|
// Example 1: Simple sequential workflow
|
|
println!("\n📋 Example 1: Sequential Workflow");
|
|
let sequential_flow = create_sequential_workflow();
|
|
let flow_id = orchestrator.execute_flow(sequential_flow).await?;
|
|
|
|
// Wait for completion and show results
|
|
wait_and_show_results(&orchestrator, flow_id, "Sequential").await;
|
|
|
|
// Example 2: Parallel workflow with convergence
|
|
println!("\n📋 Example 2: Parallel Workflow");
|
|
let parallel_flow = create_parallel_workflow();
|
|
let flow_id = orchestrator.execute_flow(parallel_flow).await?;
|
|
|
|
// Wait for completion and show results
|
|
wait_and_show_results(&orchestrator, flow_id, "Parallel").await;
|
|
|
|
// Example 3: Complex workflow with multiple dependencies
|
|
println!("\n📋 Example 3: Complex Workflow");
|
|
let complex_flow = create_complex_workflow();
|
|
let flow_id = orchestrator.execute_flow(complex_flow).await?;
|
|
|
|
// Wait for completion and show results
|
|
wait_and_show_results(&orchestrator, flow_id, "Complex").await;
|
|
|
|
// Clean up completed flows
|
|
orchestrator.cleanup_completed_flows().await;
|
|
|
|
println!("\n✅ All examples completed successfully!");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Create a simple sequential workflow
|
|
fn create_sequential_workflow() -> OrchestratedFlow {
|
|
let step1 = OrchestratedFlowStep::new("data_preparation")
|
|
.script(r#"
|
|
let data = [1, 2, 3, 4, 5];
|
|
let sum = 0;
|
|
for item in data {
|
|
sum += item;
|
|
}
|
|
let result = sum;
|
|
"#)
|
|
.context_id("sequential_context")
|
|
.worker_id("worker_1");
|
|
|
|
let step2 = OrchestratedFlowStep::new("data_processing")
|
|
.script(r#"
|
|
let processed_data = dep_1_result * 2;
|
|
let result = processed_data;
|
|
"#)
|
|
.depends_on(step1.id())
|
|
.context_id("sequential_context")
|
|
.worker_id("worker_2");
|
|
|
|
let step3 = OrchestratedFlowStep::new("data_output")
|
|
.script(r#"
|
|
let final_result = "Processed value: " + dep_2_result;
|
|
let result = final_result;
|
|
"#)
|
|
.depends_on(step2.id())
|
|
.context_id("sequential_context")
|
|
.worker_id("worker_3");
|
|
|
|
OrchestratedFlow::new("sequential_workflow")
|
|
.add_step(step1)
|
|
.add_step(step2)
|
|
.add_step(step3)
|
|
}
|
|
|
|
/// Create a parallel workflow with convergence
|
|
fn create_parallel_workflow() -> OrchestratedFlow {
|
|
let step1 = OrchestratedFlowStep::new("fetch_user_data")
|
|
.script(r#"
|
|
let user_id = 12345;
|
|
let user_name = "Alice";
|
|
let result = user_name;
|
|
"#)
|
|
.context_id("parallel_context")
|
|
.worker_id("user_service");
|
|
|
|
let step2 = OrchestratedFlowStep::new("fetch_order_data")
|
|
.script(r#"
|
|
let order_id = 67890;
|
|
let order_total = 99.99;
|
|
let result = order_total;
|
|
"#)
|
|
.context_id("parallel_context")
|
|
.worker_id("order_service");
|
|
|
|
let step3 = OrchestratedFlowStep::new("fetch_inventory_data")
|
|
.script(r#"
|
|
let product_id = "ABC123";
|
|
let stock_count = 42;
|
|
let result = stock_count;
|
|
"#)
|
|
.context_id("parallel_context")
|
|
.worker_id("inventory_service");
|
|
|
|
let step4 = OrchestratedFlowStep::new("generate_report")
|
|
.script(r#"
|
|
let report = "User: " + dep_1_result +
|
|
", Order Total: $" + dep_2_result +
|
|
", Stock: " + dep_3_result + " units";
|
|
let result = report;
|
|
"#)
|
|
.depends_on(step1.id())
|
|
.depends_on(step2.id())
|
|
.depends_on(step3.id())
|
|
.context_id("parallel_context")
|
|
.worker_id("report_service");
|
|
|
|
OrchestratedFlow::new("parallel_workflow")
|
|
.add_step(step1)
|
|
.add_step(step2)
|
|
.add_step(step3)
|
|
.add_step(step4)
|
|
}
|
|
|
|
/// Create a complex workflow with multiple dependency levels
|
|
fn create_complex_workflow() -> OrchestratedFlow {
|
|
// Level 1: Initial data gathering
|
|
let step1 = OrchestratedFlowStep::new("load_config")
|
|
.script(r#"
|
|
let config = #{
|
|
api_url: "https://api.example.com",
|
|
timeout: 30,
|
|
retries: 3
|
|
};
|
|
let result = config.api_url;
|
|
"#)
|
|
.context_id("complex_context")
|
|
.worker_id("config_service");
|
|
|
|
let step2 = OrchestratedFlowStep::new("authenticate")
|
|
.script(r#"
|
|
let token = "auth_token_12345";
|
|
let expires_in = 3600;
|
|
let result = token;
|
|
"#)
|
|
.context_id("complex_context")
|
|
.worker_id("auth_service");
|
|
|
|
// Level 2: Data fetching (depends on config and auth)
|
|
let step3 = OrchestratedFlowStep::new("fetch_customers")
|
|
.script(r#"
|
|
let api_url = dep_1_result;
|
|
let auth_token = dep_2_result;
|
|
let customers = ["Customer A", "Customer B", "Customer C"];
|
|
let result = customers.len();
|
|
"#)
|
|
.depends_on(step1.id())
|
|
.depends_on(step2.id())
|
|
.context_id("complex_context")
|
|
.worker_id("customer_service");
|
|
|
|
let step4 = OrchestratedFlowStep::new("fetch_products")
|
|
.script(r#"
|
|
let api_url = dep_1_result;
|
|
let auth_token = dep_2_result;
|
|
let products = ["Product X", "Product Y", "Product Z"];
|
|
let result = products.len();
|
|
"#)
|
|
.depends_on(step1.id())
|
|
.depends_on(step2.id())
|
|
.context_id("complex_context")
|
|
.worker_id("product_service");
|
|
|
|
// Level 3: Data processing (depends on fetched data)
|
|
let step5 = OrchestratedFlowStep::new("calculate_metrics")
|
|
.script(r#"
|
|
let customer_count = dep_3_result;
|
|
let product_count = dep_4_result;
|
|
let ratio = customer_count / product_count;
|
|
let result = ratio;
|
|
"#)
|
|
.depends_on(step3.id())
|
|
.depends_on(step4.id())
|
|
.context_id("complex_context")
|
|
.worker_id("analytics_service");
|
|
|
|
// Level 4: Final reporting
|
|
let step6 = OrchestratedFlowStep::new("generate_dashboard")
|
|
.script(r#"
|
|
let customer_count = dep_3_result;
|
|
let product_count = dep_4_result;
|
|
let ratio = dep_5_result;
|
|
let dashboard = "Dashboard: " + customer_count + " customers, " +
|
|
product_count + " products, ratio: " + ratio;
|
|
let result = dashboard;
|
|
"#)
|
|
.depends_on(step3.id())
|
|
.depends_on(step4.id())
|
|
.depends_on(step5.id())
|
|
.context_id("complex_context")
|
|
.worker_id("dashboard_service");
|
|
|
|
OrchestratedFlow::new("complex_workflow")
|
|
.add_step(step1)
|
|
.add_step(step2)
|
|
.add_step(step3)
|
|
.add_step(step4)
|
|
.add_step(step5)
|
|
.add_step(step6)
|
|
}
|
|
|
|
/// Wait for flow completion and show results
|
|
async fn wait_and_show_results(
|
|
orchestrator: &Orchestrator<LocalInterface>,
|
|
flow_id: u32,
|
|
workflow_name: &str,
|
|
) {
|
|
println!(" ⏳ Executing {} workflow (ID: {})...", workflow_name, flow_id);
|
|
|
|
// Poll for completion
|
|
loop {
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
|
|
|
|
if let Some(execution) = orchestrator.get_flow_status(flow_id).await {
|
|
match execution.status {
|
|
FlowStatus::Completed => {
|
|
println!(" ✅ {} workflow completed successfully!", workflow_name);
|
|
println!(" 📊 Executed {} steps in {:?}",
|
|
execution.completed_steps.len(),
|
|
execution.completed_at.unwrap() - execution.started_at);
|
|
|
|
// Show step results
|
|
for (step_id, outputs) in &execution.step_results {
|
|
if let Some(result) = outputs.get("result") {
|
|
let step_name = execution.flow.orchestrated_steps
|
|
.iter()
|
|
.find(|s| s.id() == *step_id)
|
|
.map(|s| s.flow_step.name.as_str())
|
|
.unwrap_or("unknown");
|
|
println!(" 📝 Step '{}': {}", step_name, result);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
FlowStatus::Failed => {
|
|
println!(" ❌ {} workflow failed!", workflow_name);
|
|
if !execution.failed_steps.is_empty() {
|
|
println!(" 💥 Failed steps: {:?}", execution.failed_steps);
|
|
}
|
|
break;
|
|
}
|
|
FlowStatus::Running => {
|
|
print!(".");
|
|
std::io::Write::flush(&mut std::io::stdout()).unwrap();
|
|
}
|
|
FlowStatus::Pending => {
|
|
println!(" ⏸️ {} workflow is pending...", workflow_name);
|
|
}
|
|
}
|
|
} else {
|
|
println!(" ❓ {} workflow not found!", workflow_name);
|
|
break;
|
|
}
|
|
}
|
|
} |