- Simplified RunnerConfig to just name, command, and optional env - Removed RunnerType and ProcessManagerType enums - Removed db_path, redis_url, binary_path from config - Made runner name also serve as queue name (no separate queue param) - Added secret-based authentication to all runner management methods - Created comprehensive osiris_openrpc example - Archived old examples to _archive/ - Updated client API to match simplified supervisor interface
		
			
				
	
	
		
			204 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
//! Simple End-to-End Example
 | 
						|
//!
 | 
						|
//! A minimal example showing supervisor + runner + client workflow.
 | 
						|
//!
 | 
						|
//! Prerequisites:
 | 
						|
//! - Redis running on localhost:6379
 | 
						|
//!
 | 
						|
//! Usage:
 | 
						|
//! ```bash
 | 
						|
//! # Terminal 1: Start Redis
 | 
						|
//! redis-server
 | 
						|
//!
 | 
						|
//! # Terminal 2: Run this example
 | 
						|
//! RUST_LOG=info cargo run --example simple_e2e
 | 
						|
//! ```
 | 
						|
 | 
						|
use anyhow::Result;
 | 
						|
use log::info;
 | 
						|
use std::time::Duration;
 | 
						|
use tokio::time::sleep;
 | 
						|
use hero_supervisor_openrpc_client::{SupervisorClient, JobBuilder};
 | 
						|
 | 
						|
#[tokio::main]
 | 
						|
async fn main() -> Result<()> {
 | 
						|
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
 | 
						|
    
 | 
						|
    println!("\n╔════════════════════════════════════════╗");
 | 
						|
    println!("║  Simple End-to-End Demo               ║");
 | 
						|
    println!("╚════════════════════════════════════════╝\n");
 | 
						|
    
 | 
						|
    let supervisor_url = "http://localhost:3030";
 | 
						|
    let runner_id = "test_runner";
 | 
						|
    let secret = "admin_secret";
 | 
						|
    
 | 
						|
    // Create supervisor client
 | 
						|
    let client = SupervisorClient::new(supervisor_url)?;
 | 
						|
    
 | 
						|
    println!("📝 Prerequisites:");
 | 
						|
    println!("   1. Redis running on localhost:6379");
 | 
						|
    println!("   2. Supervisor running on {}", supervisor_url);
 | 
						|
    println!("   3. Runner '{}' registered and running\n", runner_id);
 | 
						|
    
 | 
						|
    println!("💡 To start the supervisor:");
 | 
						|
    println!("   cargo run --bin hero-supervisor -- --redis-url redis://localhost:6379\n");
 | 
						|
    
 | 
						|
    println!("💡 To start a runner:");
 | 
						|
    println!("   cd /Users/timurgordon/code/git.ourworld.tf/herocode/runner_rust");
 | 
						|
    println!("   cargo run --bin runner_osis -- {} --redis-url redis://localhost:6379\n", runner_id);
 | 
						|
    
 | 
						|
    println!("⏳ Waiting 3 seconds for you to start the prerequisites...\n");
 | 
						|
    sleep(Duration::from_secs(3)).await;
 | 
						|
    
 | 
						|
    // Register runner
 | 
						|
    println!("📋 Step 1: Registering Runner");
 | 
						|
    println!("─────────────────────────────────────────");
 | 
						|
    
 | 
						|
    let queue = format!("hero:q:work:type:osis:group:default:inst:{}", runner_id);
 | 
						|
    match client.register_runner(secret, runner_id, &queue).await {
 | 
						|
        Ok(_) => {
 | 
						|
            println!("✅ Runner registered successfully");
 | 
						|
        }
 | 
						|
        Err(e) => {
 | 
						|
            println!("⚠️  Registration error: {} (runner might already be registered)", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    sleep(Duration::from_secs(1)).await;
 | 
						|
    
 | 
						|
    // Run a simple job
 | 
						|
    println!("\n📋 Step 2: Running a Simple Job (Blocking)");
 | 
						|
    println!("─────────────────────────────────────────");
 | 
						|
    
 | 
						|
    let job = JobBuilder::new()
 | 
						|
        .caller_id("simple_demo")
 | 
						|
        .context_id("demo_context")
 | 
						|
        .payload(r#"
 | 
						|
            let message = "Hello from the runner!";
 | 
						|
            let number = 42;
 | 
						|
            to_json(#{
 | 
						|
                message: message,
 | 
						|
                number: number,
 | 
						|
                timestamp: timestamp()
 | 
						|
            })
 | 
						|
        "#)
 | 
						|
        .runner(runner_id)
 | 
						|
        .executor("rhai")
 | 
						|
        .timeout(30)
 | 
						|
        .build()?;
 | 
						|
    
 | 
						|
    let job_id = job.id.clone();
 | 
						|
    info!("Sending job with ID: {}", job_id);
 | 
						|
    
 | 
						|
    match client.job_run(secret, job, Some(30)).await {
 | 
						|
        Ok(response) => {
 | 
						|
            println!("✅ Job completed!");
 | 
						|
            if let Some(result) = response.result {
 | 
						|
                println!("   Result: {}", result);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Job failed: {}", e);
 | 
						|
            return Ok(());
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Run another job (calculation)
 | 
						|
    println!("\n📋 Step 3: Running a Calculation Job");
 | 
						|
    println!("─────────────────────────────────────────");
 | 
						|
    
 | 
						|
    let calc_job = JobBuilder::new()
 | 
						|
        .caller_id("simple_demo")
 | 
						|
        .context_id("demo_context")
 | 
						|
        .payload(r#"
 | 
						|
            let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 | 
						|
            let sum = 0;
 | 
						|
            let product = 1;
 | 
						|
            
 | 
						|
            for n in numbers {
 | 
						|
                sum += n;
 | 
						|
                product *= n;
 | 
						|
            }
 | 
						|
            
 | 
						|
            to_json(#{
 | 
						|
                sum: sum,
 | 
						|
                product: product,
 | 
						|
                count: numbers.len(),
 | 
						|
                average: sum / numbers.len()
 | 
						|
            })
 | 
						|
        "#)
 | 
						|
        .runner(runner_id)
 | 
						|
        .executor("rhai")
 | 
						|
        .timeout(30)
 | 
						|
        .build()?;
 | 
						|
    
 | 
						|
    let calc_job_id = calc_job.id.clone();
 | 
						|
    info!("Sending calculation job with ID: {}", calc_job_id);
 | 
						|
    
 | 
						|
    match client.job_run(secret, calc_job, Some(30)).await {
 | 
						|
        Ok(response) => {
 | 
						|
            println!("✅ Calculation completed!");
 | 
						|
            if let Some(result) = response.result {
 | 
						|
                println!("   Result: {}", result);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Calculation failed: {}", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Start a non-blocking job
 | 
						|
    println!("\n📋 Step 4: Starting a Non-Blocking Job");
 | 
						|
    println!("─────────────────────────────────────────");
 | 
						|
    
 | 
						|
    let async_job = JobBuilder::new()
 | 
						|
        .caller_id("simple_demo")
 | 
						|
        .context_id("demo_context")
 | 
						|
        .payload(r#"
 | 
						|
            let result = "This job was started asynchronously";
 | 
						|
            to_json(result)
 | 
						|
        "#)
 | 
						|
        .runner(runner_id)
 | 
						|
        .executor("rhai")
 | 
						|
        .timeout(30)
 | 
						|
        .build()?;
 | 
						|
    
 | 
						|
    let async_job_id = async_job.id.clone();
 | 
						|
    info!("Starting async job with ID: {}", async_job_id);
 | 
						|
    
 | 
						|
    match client.job_start(secret, async_job).await {
 | 
						|
        Ok(response) => {
 | 
						|
            println!("✅ Job started!");
 | 
						|
            println!("   Job ID: {} (running in background)", response.job_id);
 | 
						|
            println!("   Status: {}", response.status);
 | 
						|
        }
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to start job: {}", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Summary
 | 
						|
    println!("\n╔════════════════════════════════════════╗");
 | 
						|
    println!("║  Demo Summary                          ║");
 | 
						|
    println!("╚════════════════════════════════════════╝");
 | 
						|
    println!("✅ Runner registered: {}", runner_id);
 | 
						|
    println!("✅ Blocking jobs completed: 2");
 | 
						|
    println!("✅ Non-blocking jobs started: 1");
 | 
						|
    println!("\n🎉 Demo completed successfully!\n");
 | 
						|
    
 | 
						|
    println!("📚 What happened:");
 | 
						|
    println!("   1. Registered a runner with the supervisor");
 | 
						|
    println!("   2. Sent jobs with Rhai scripts to execute");
 | 
						|
    println!("   3. Supervisor queued jobs to the runner");
 | 
						|
    println!("   4. Runner executed the scripts and returned results");
 | 
						|
    println!("   5. Client received results (for blocking jobs)\n");
 | 
						|
    
 | 
						|
    println!("🔍 Key Concepts:");
 | 
						|
    println!("   • job.run  = Execute and wait for result (blocking)");
 | 
						|
    println!("   • job.start = Start and return immediately (non-blocking)");
 | 
						|
    println!("   • Jobs contain Rhai scripts that run on the runner");
 | 
						|
    println!("   • Supervisor coordinates job distribution via Redis\n");
 | 
						|
    
 | 
						|
    Ok(())
 | 
						|
}
 |