//! 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> { // 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(job_ids) => { println!("✅ Found {} jobs in the system:", job_ids.len()); for (i, job_id) in job_ids.iter().take(10).enumerate() { println!(" {}. {}", i + 1, job_id); } if job_ids.len() > 10 { println!(" ... and {} more", job_ids.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()); } }