- 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
		
			
				
	
	
		
			270 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
//! Examples demonstrating the new job API workflows
 | 
						|
//! 
 | 
						|
//! This example shows how to use the new job API methods:
 | 
						|
//! - jobs.create: Create a job without queuing
 | 
						|
//! - jobs.list: List all jobs
 | 
						|
//! - job.run: Run a job and get result immediately
 | 
						|
//! - job.start: Start a created job
 | 
						|
//! - job.status: Get job status (non-blocking)
 | 
						|
//! - job.result: Get job result (blocking)
 | 
						|
 | 
						|
use hero_supervisor_openrpc_client::{SupervisorClient, JobBuilder, JobResult};
 | 
						|
use std::time::Duration;
 | 
						|
use tokio::time::sleep;
 | 
						|
 | 
						|
#[tokio::main]
 | 
						|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
 | 
						|
    // Initialize logging
 | 
						|
    env_logger::init();
 | 
						|
    
 | 
						|
    println!("🚀 Hero Supervisor Job API Examples");
 | 
						|
    println!("===================================\n");
 | 
						|
 | 
						|
    // Create client
 | 
						|
    let client = SupervisorClient::new("http://localhost:3030")?;
 | 
						|
    let secret = "user-secret-456"; // Use a user secret for job operations
 | 
						|
 | 
						|
    // Test connection
 | 
						|
    println!("📡 Testing connection...");
 | 
						|
    match client.discover().await {
 | 
						|
        Ok(_) => println!("✅ Connected to supervisor\n"),
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to connect: {}", e);
 | 
						|
            println!("Make sure the supervisor is running with: ./supervisor --config examples/supervisor/config.toml\n");
 | 
						|
            return Ok(());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Example 1: Fire-and-forget job execution
 | 
						|
    println!("🔥 Example 1: Fire-and-forget job execution");
 | 
						|
    println!("--------------------------------------------");
 | 
						|
    
 | 
						|
    let job = JobBuilder::new()
 | 
						|
        .caller_id("example_client")
 | 
						|
        .context_id("fire_and_forget")
 | 
						|
        .payload("echo 'Hello from fire-and-forget job!'")
 | 
						|
        .executor("osis")
 | 
						|
        .runner("osis_runner_1")
 | 
						|
        .timeout(30)
 | 
						|
        .build()?;
 | 
						|
 | 
						|
    println!("Running job immediately...");
 | 
						|
    match client.job_run(secret, job).await {
 | 
						|
        Ok(JobResult::Success { success }) => {
 | 
						|
            println!("✅ Job completed successfully:");
 | 
						|
            println!("   Output: {}", success);
 | 
						|
        },
 | 
						|
        Ok(JobResult::Error { error }) => {
 | 
						|
            println!("❌ Job failed:");
 | 
						|
            println!("   Error: {}", error);
 | 
						|
        },
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ API call failed: {}", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
 | 
						|
    // Example 2: Asynchronous job processing
 | 
						|
    println!("⏰ Example 2: Asynchronous job processing");
 | 
						|
    println!("------------------------------------------");
 | 
						|
 | 
						|
    let job = JobBuilder::new()
 | 
						|
        .caller_id("example_client")
 | 
						|
        .context_id("async_processing")
 | 
						|
        .payload("sleep 2 && echo 'Hello from async job!'")
 | 
						|
        .executor("osis")
 | 
						|
        .runner("osis_runner_1")
 | 
						|
        .timeout(60)
 | 
						|
        .build()?;
 | 
						|
 | 
						|
    // Step 1: Create the job
 | 
						|
    println!("1. Creating job...");
 | 
						|
    let job_id = match client.jobs_create(secret, job).await {
 | 
						|
        Ok(id) => {
 | 
						|
            println!("✅ Job created with ID: {}", id);
 | 
						|
            id
 | 
						|
        },
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to create job: {}", e);
 | 
						|
            return Ok(());
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    // Step 2: Start the job
 | 
						|
    println!("2. Starting job...");
 | 
						|
    match client.job_start(secret, &job_id).await {
 | 
						|
        Ok(_) => println!("✅ Job started"),
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to start job: {}", e);
 | 
						|
            return Ok(());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Step 3: Poll for completion (non-blocking)
 | 
						|
    println!("3. Monitoring job progress...");
 | 
						|
    let mut attempts = 0;
 | 
						|
    let max_attempts = 30; // 30 seconds max
 | 
						|
 | 
						|
    loop {
 | 
						|
        attempts += 1;
 | 
						|
        
 | 
						|
        match client.job_status(&job_id).await {
 | 
						|
            Ok(status) => {
 | 
						|
                println!("   Status: {} (attempt {})", status.status, attempts);
 | 
						|
                
 | 
						|
                if status.status == "completed" || status.status == "failed" || status.status == "timeout" {
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                
 | 
						|
                if attempts >= max_attempts {
 | 
						|
                    println!("   ⏰ Timeout waiting for job completion");
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                
 | 
						|
                sleep(Duration::from_secs(1)).await;
 | 
						|
            },
 | 
						|
            Err(e) => {
 | 
						|
                println!("   ❌ Failed to get job status: {}", e);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Step 4: Get the result
 | 
						|
    println!("4. Getting job result...");
 | 
						|
    match client.job_result(&job_id).await {
 | 
						|
        Ok(JobResult::Success { success }) => {
 | 
						|
            println!("✅ Job completed successfully:");
 | 
						|
            println!("   Output: {}", success);
 | 
						|
        },
 | 
						|
        Ok(JobResult::Error { error }) => {
 | 
						|
            println!("❌ Job failed:");
 | 
						|
            println!("   Error: {}", error);
 | 
						|
        },
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to get job result: {}", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
 | 
						|
    // Example 3: Batch job processing
 | 
						|
    println!("📦 Example 3: Batch job processing");
 | 
						|
    println!("-----------------------------------");
 | 
						|
 | 
						|
    let job_specs = vec![
 | 
						|
        ("echo 'Batch job 1'", "batch_1"),
 | 
						|
        ("echo 'Batch job 2'", "batch_2"),
 | 
						|
        ("echo 'Batch job 3'", "batch_3"),
 | 
						|
    ];
 | 
						|
 | 
						|
    let mut job_ids = Vec::new();
 | 
						|
 | 
						|
    // Create all jobs
 | 
						|
    println!("Creating batch jobs...");
 | 
						|
    for (i, (payload, context)) in job_specs.iter().enumerate() {
 | 
						|
        let job = JobBuilder::new()
 | 
						|
            .caller_id("example_client")
 | 
						|
            .context_id(context)
 | 
						|
            .payload(payload)
 | 
						|
            .executor("osis")
 | 
						|
            .runner("osis_runner_1")
 | 
						|
            .timeout(30)
 | 
						|
            .build()?;
 | 
						|
 | 
						|
        match client.jobs_create(secret, job).await {
 | 
						|
            Ok(job_id) => {
 | 
						|
                println!("✅ Created job {}: {}", i + 1, job_id);
 | 
						|
                job_ids.push(job_id);
 | 
						|
            },
 | 
						|
            Err(e) => {
 | 
						|
                println!("❌ Failed to create job {}: {}", i + 1, e);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Start all jobs
 | 
						|
    println!("Starting all batch jobs...");
 | 
						|
    for (i, job_id) in job_ids.iter().enumerate() {
 | 
						|
        match client.job_start(secret, job_id).await {
 | 
						|
            Ok(_) => println!("✅ Started job {}", i + 1),
 | 
						|
            Err(e) => println!("❌ Failed to start job {}: {}", i + 1, e),
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // Collect results
 | 
						|
    println!("Collecting results...");
 | 
						|
    for (i, job_id) in job_ids.iter().enumerate() {
 | 
						|
        match client.job_result(job_id).await {
 | 
						|
            Ok(JobResult::Success { success }) => {
 | 
						|
                println!("✅ Job {} result: {}", i + 1, success);
 | 
						|
            },
 | 
						|
            Ok(JobResult::Error { error }) => {
 | 
						|
                println!("❌ Job {} failed: {}", i + 1, error);
 | 
						|
            },
 | 
						|
            Err(e) => {
 | 
						|
                println!("❌ Failed to get result for job {}: {}", i + 1, e);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
 | 
						|
    // Example 4: List all jobs
 | 
						|
    println!("📋 Example 4: Listing all jobs");
 | 
						|
    println!("-------------------------------");
 | 
						|
 | 
						|
    match client.jobs_list().await {
 | 
						|
        Ok(jobs) => {
 | 
						|
            println!("✅ Found {} jobs in the system:", jobs.len());
 | 
						|
            for (i, job) in jobs.iter().take(10).enumerate() {
 | 
						|
                println!("   {}. {}", i + 1, job.id);
 | 
						|
            }
 | 
						|
            if jobs.len() > 10 {
 | 
						|
                println!("   ... and {} more", jobs.len() - 10);
 | 
						|
            }
 | 
						|
        },
 | 
						|
        Err(e) => {
 | 
						|
            println!("❌ Failed to list jobs: {}", e);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    println!();
 | 
						|
 | 
						|
    println!("🎉 All examples completed!");
 | 
						|
    println!("\nAPI Convention Summary:");
 | 
						|
    println!("- jobs.create: Create job without queuing");
 | 
						|
    println!("- jobs.list: List all job IDs");
 | 
						|
    println!("- job.run: Run job and return result immediately");
 | 
						|
    println!("- job.start: Start a created job");
 | 
						|
    println!("- job.status: Get job status (non-blocking)");
 | 
						|
    println!("- job.result: Get job result (blocking)");
 | 
						|
 | 
						|
    Ok(())
 | 
						|
}
 | 
						|
 | 
						|
#[cfg(test)]
 | 
						|
mod tests {
 | 
						|
    use super::*;
 | 
						|
 | 
						|
    #[test]
 | 
						|
    fn test_job_builder() {
 | 
						|
        let job = JobBuilder::new()
 | 
						|
            .caller_id("test")
 | 
						|
            .context_id("test")
 | 
						|
            .payload("echo 'test'")
 | 
						|
            .executor("osis")
 | 
						|
            .runner("test_runner")
 | 
						|
            .build();
 | 
						|
 | 
						|
        assert!(job.is_ok());
 | 
						|
        let job = job.unwrap();
 | 
						|
        assert_eq!(job.caller_id, "test");
 | 
						|
        assert_eq!(job.context_id, "test");
 | 
						|
        assert_eq!(job.payload, "echo 'test'");
 | 
						|
    }
 | 
						|
 | 
						|
    #[tokio::test]
 | 
						|
    async fn test_client_creation() {
 | 
						|
        let client = SupervisorClient::new("http://localhost:3030");
 | 
						|
        assert!(client.is_ok());
 | 
						|
    }
 | 
						|
}
 |