feat: dagrunner, initial version
This commit is contained in:
122 files changed
+23101
No files matched your search
@@ -0,0 +1,150 @@
|
||||
//! # Pattern: Conditional Execution with Data Validation
|
||||
//!
|
||||
//! This example demonstrates how to implement conditional logic in DAGs by using
|
||||
//! simple data transformations rather than traditional Result types.
|
||||
//!
|
||||
//! ## What You'll Learn
|
||||
//! - How to implement validation logic in parallel tasks
|
||||
//! - How to use return values for conditional behavior (e.g., 0 for invalid)
|
||||
//! - How to categorize and branch based on computed values
|
||||
//! - How to aggregate results from multiple conditional branches
|
||||
//!
|
||||
//! ## Workflow Diagram
|
||||
//! ```text
|
||||
//! VALIDATE CATEGORIZE SUMMARIZE
|
||||
//! ┌─────────────┐ ┌──────────────┐
|
||||
//! │ Validate(10)│────20──►│Categorize(25)│────"low"────┐
|
||||
//! └─────────────┘ └──────────────┘ │
|
||||
//! │
|
||||
//! ┌─────────────┐ ┌──────────────┐ │
|
||||
//! │ Validate(-5)│────0───►│Categorize(25)│──"invalid"──┼──►┌────────────┐
|
||||
//! └─────────────┘ └──────────────┘ │ │ Summarize │
|
||||
//! │ └────────────┘
|
||||
//! ┌─────────────┐ ┌──────────────┐ │
|
||||
//! │ Validate(20)│────40──►│Categorize(25)│────"high"───┘
|
||||
//! └─────────────┘ └──────────────┘
|
||||
//! ```
|
||||
//!
|
||||
//! ## Key Concepts
|
||||
//! - **Validation as transformation**: Invalid inputs become sentinel values (0)
|
||||
//! - **Parallel validation**: All inputs validated simultaneously
|
||||
//! - **Data-driven branching**: Categorization based on computed values
|
||||
//! - **Type-safe aggregation**: All branches produce the same type (String)
|
||||
//!
|
||||
//! ## Use Cases
|
||||
//! - Input validation pipelines
|
||||
//! - Multi-stage data cleaning
|
||||
//! - Classification and categorization workflows
|
||||
//! - Quality control systems
|
||||
//! - Data preprocessing for ML pipelines
|
||||
//!
|
||||
//! ## Running This Example
|
||||
//! ```bash
|
||||
//! cargo run --example conditional_workflow
|
||||
//! ```
|
||||
//!
|
||||
//! ## Expected Output
|
||||
//! ```text
|
||||
//! Processing and categorizing inputs in parallel...
|
||||
//!
|
||||
//! Valid input 10: doubling to 20
|
||||
//! Invalid input -5: returning 0
|
||||
//! Valid input 20: doubling to 40
|
||||
//!
|
||||
//! Final summary: Categories: [low, invalid, high]
|
||||
//! Expected: Categories: [low, invalid, high]
|
||||
//! ```
|
||||
|
||||
use dagx::{task, DagResult, DagRunner, Task};
|
||||
|
||||
// Task that validates and processes input
|
||||
struct ValidateAndDouble {
|
||||
value: i32,
|
||||
}
|
||||
|
||||
impl ValidateAndDouble {
|
||||
fn new(value: i32) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
#[task]
|
||||
impl ValidateAndDouble {
|
||||
async fn run(&mut self) -> i32 {
|
||||
if self.value > 0 {
|
||||
println!("Valid input {}: doubling to {}", self.value, self.value * 2);
|
||||
self.value * 2
|
||||
} else {
|
||||
println!("Invalid input {}: returning 0", self.value);
|
||||
0 // Return 0 for invalid inputs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Task that categorizes a number
|
||||
struct Categorize {
|
||||
threshold: i32,
|
||||
}
|
||||
|
||||
impl Categorize {
|
||||
fn new(threshold: i32) -> Self {
|
||||
Self { threshold }
|
||||
}
|
||||
}
|
||||
|
||||
#[task]
|
||||
impl Categorize {
|
||||
async fn run(&mut self, value: &i32) -> String {
|
||||
if *value == 0 {
|
||||
"invalid".to_string()
|
||||
} else if *value >= self.threshold {
|
||||
"high".to_string()
|
||||
} else {
|
||||
"low".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Task that combines categorization results
|
||||
struct SummarizeResults;
|
||||
|
||||
#[task]
|
||||
impl SummarizeResults {
|
||||
async fn run(cat1: &String, cat2: &String, cat3: &String) -> String {
|
||||
format!("Categories: [{}, {}, {}]", cat1, cat2, cat3)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> DagResult<()> {
|
||||
let dag = DagRunner::new();
|
||||
|
||||
println!("Processing and categorizing inputs in parallel...\n");
|
||||
|
||||
// Validate and process multiple inputs in parallel
|
||||
let processed1 = dag.add_task(ValidateAndDouble::new(10)); // Valid: 20
|
||||
let processed2 = dag.add_task(ValidateAndDouble::new(-5)); // Invalid: 0
|
||||
let processed3 = dag.add_task(ValidateAndDouble::new(20)); // Valid: 40
|
||||
|
||||
// Categorize each result (also parallel, threshold = 25)
|
||||
let cat1 = dag.add_task(Categorize::new(25)).depends_on(&processed1); // 20 < 25 = "low"
|
||||
let cat2 = dag.add_task(Categorize::new(25)).depends_on(&processed2); // 0 = "invalid"
|
||||
let cat3 = dag.add_task(Categorize::new(25)).depends_on(&processed3); // 40 >= 25 = "high"
|
||||
|
||||
// Combine results
|
||||
let summary = dag
|
||||
.add_task(SummarizeResults)
|
||||
.depends_on((&cat1, &cat2, &cat3));
|
||||
|
||||
// Execute
|
||||
dag.run(|fut| {
|
||||
tokio::spawn(fut);
|
||||
})
|
||||
.await?;
|
||||
|
||||
// Display results
|
||||
println!("\nFinal summary: {}", dag.get(summary)?);
|
||||
println!("Expected: Categories: [low, invalid, high]");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user