Files
supervisor/examples/osiris_openrpc/main.rs
Timur Gordon a47157aa71 fix: keep OpenRPC ServerHandle alive to prevent server shutdown
The ServerHandle was being dropped immediately after spawning, causing the
OpenRPC server to shut down. Now we properly await handle.stopped() to keep
the server running.
2025-10-27 14:34:22 +01:00

254 lines
9.8 KiB
Rust

///! Comprehensive OSIRIS + OpenRPC Example
///!
///! This example demonstrates:
///! 1. Starting a Hero Supervisor with OpenRPC server
///! 2. Starting an OSIRIS runner
///! 3. Registering the runner with the supervisor
///! 4. Dispatching multiple OSIRIS jobs via OpenRPC
///! 5. Monitoring job execution
///! 6. Graceful shutdown
///!
///! Usage:
///! ```bash
///! cargo run --example osiris_openrpc
///! ```
use hero_supervisor_openrpc_client::{SupervisorClient, RunnerConfig, JobBuilder};
use std::time::Duration;
use escargot::CargoBuild;
use std::process::Stdio;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 OSIRIS + OpenRPC Comprehensive Example");
println!("=========================================\n");
// ========================================================================
// STEP 1: Build and start supervisor with OpenRPC
// ========================================================================
println!("Step 1: Building and starting supervisor");
println!("─────────────────────────────────────────────────────────────\n");
let supervisor_binary = CargoBuild::new()
.bin("supervisor")
.current_release()
.manifest_path("../supervisor/Cargo.toml")
.run()?;
println!("✅ Supervisor binary built");
let mut supervisor = supervisor_binary.command()
.arg("--redis-url")
.arg("redis://localhost:6379")
.arg("--port")
.arg("3030")
.arg("--admin-secret")
.arg("admin_secret")
.arg("--user-secret")
.arg("user_secret")
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()?;
println!("✅ Supervisor started on port 3030");
println!("⏳ Waiting for supervisor to initialize...");
sleep(Duration::from_secs(5)).await;
// Check if supervisor is still running
match supervisor.try_wait()? {
Some(status) => {
return Err(format!("Supervisor exited early with status: {}", status).into());
}
None => {
println!("✅ Supervisor is running");
}
}
// ========================================================================
// STEP 2: Build OSIRIS runner
// ========================================================================
println!("\nStep 2: Building OSIRIS runner");
println!("─────────────────────────────────────────────────────────────\n");
let runner_binary = CargoBuild::new()
.bin("runner_osiris")
.current_release()
.manifest_path("../runner_rust/Cargo.toml")
.run()?;
println!("✅ OSIRIS runner binary built");
// ========================================================================
// STEP 3: Connect OpenRPC client
// ========================================================================
println!("\nStep 3: Connecting OpenRPC client");
println!("─────────────────────────────────────────────────────────────\n");
let client = SupervisorClient::new("http://127.0.0.1:3030")?;
println!("✅ Connected to supervisor\n");
// ========================================================================
// STEP 4: Register and start OSIRIS runner
// ========================================================================
println!("Step 4: Registering OSIRIS runner");
println!("─────────────────────────────────────────────────────────────\n");
let runner_path = runner_binary.path().to_string_lossy();
let db_path = "/tmp/osiris_openrpc.db";
let command = format!(
"{} osiris_runner --db-path {} --redis-url redis://localhost:6379",
runner_path, db_path
);
let runner_config = RunnerConfig {
name: "osiris_runner".to_string(),
command,
env: None,
};
client.add_runner("admin_secret", runner_config).await?;
println!("✅ Runner registered: osiris_runner");
client.start_runner("admin_secret", "osiris_runner").await?;
println!("✅ Runner started\n");
sleep(Duration::from_secs(2)).await;
// ========================================================================
// STEP 5: Load job scripts
// ========================================================================
println!("Step 5: Loading job scripts");
println!("─────────────────────────────────────────────────────────────\n");
let note_script = std::fs::read_to_string("examples/osiris_openrpc/note.rhai")?;
let event_script = std::fs::read_to_string("examples/osiris_openrpc/event.rhai")?;
let query_script = std::fs::read_to_string("examples/osiris_openrpc/query.rhai")?;
let access_denied_script = std::fs::read_to_string("examples/osiris_openrpc/access_denied.rhai")?;
println!("✅ Loaded 4 job scripts\n");
// ========================================================================
// STEP 6: Dispatch jobs via OpenRPC
// ========================================================================
println!("Step 6: Dispatching jobs");
println!("─────────────────────────────────────────────────────────────\n");
// Job 1: Create Note
println!("📝 Job 1: Creating Note...");
let job1 = JobBuilder::new()
.caller_id("openrpc_client")
.context_id("osiris_demo")
.payload(&note_script)
.runner("osiris_runner")
.executor("rhai")
.timeout(30)
.signature("alice", "")
.signature("bob", "")
.build()?;
let job1_result = client.run_job("user_secret", job1).await;
match job1_result {
Ok(result) => println!("{:?}\n", result),
Err(e) => println!("❌ Job failed: {}\n", e),
}
sleep(Duration::from_secs(1)).await;
// Job 2: Create Event
println!("📅 Job 2: Creating Event...");
let job2 = JobBuilder::new()
.caller_id("openrpc_client")
.context_id("osiris_demo")
.payload(&event_script)
.runner("osiris_runner")
.executor("rhai")
.timeout(30)
.signature("alice", "")
.signature("bob", "")
.build()?;
let job2_result = client.run_job("user_secret", job2).await;
match job2_result {
Ok(result) => println!("{:?}\n", result),
Err(e) => println!("❌ Job failed: {}\n", e),
}
sleep(Duration::from_secs(1)).await;
// Job 3: Query Data
println!("🔍 Job 3: Querying Data...");
let job3 = JobBuilder::new()
.caller_id("openrpc_client")
.context_id("osiris_demo")
.payload(&query_script)
.runner("osiris_runner")
.executor("rhai")
.timeout(30)
.signature("alice", "")
.signature("bob", "")
.signature("charlie", "")
.build()?;
let job3_result = client.run_job("user_secret", job3).await;
match job3_result {
Ok(result) => println!("{:?}\n", result),
Err(e) => println!("❌ Job failed: {}\n", e),
}
sleep(Duration::from_secs(1)).await;
// Job 4: Access Control Test (should fail)
println!("🔒 Job 4: Testing Access Control (expected to fail)...");
let job4 = JobBuilder::new()
.caller_id("openrpc_client")
.context_id("osiris_demo")
.payload(&access_denied_script)
.runner("osiris_runner")
.executor("rhai")
.timeout(30)
.signature("alice", "")
.signature("bob", "")
.signature("charlie", "")
.build()?;
let job4_result = client.run_job("user_secret", job4).await;
match job4_result {
Ok(result) => println!("❌ Unexpected success: {:?}\n", result),
Err(e) => println!("✅ Access denied as expected: {}\n", e),
}
// ========================================================================
// STEP 7: Check runner status
// ========================================================================
println!("\nStep 7: Checking runner status");
println!("─────────────────────────────────────────────────────────────\n");
let status = client.get_runner_status("admin_secret", "osiris_runner").await?;
println!("Runner status: {:?}\n", status);
// ========================================================================
// STEP 8: Cleanup
// ========================================================================
println!("Step 8: Cleanup");
println!("─────────────────────────────────────────────────────────────\n");
client.stop_runner("admin_secret", "osiris_runner", false).await?;
println!("✅ Runner stopped");
client.remove_runner("admin_secret", "osiris_runner").await?;
println!("✅ Runner removed");
supervisor.kill()?;
println!("✅ Supervisor stopped");
println!("\n✨ Example completed successfully!");
Ok(())
}