rhailib/examples/dedicated_reply_queue_demo.rs
2025-06-19 02:32:56 +03:00

120 lines
4.3 KiB
Rust

use log::{debug, error, info};
use rhai::Engine;
use rhai_client::{RhaiClient, RhaiClientError}; // RhaiTaskDetails is now used for its fields
use rhailib_worker::spawn_rhai_worker;
use std::time::Duration;
use tokio::sync::mpsc;
use uuid::Uuid; // Added for generating task_id
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
let redis_url = "redis://127.0.0.1/";
let circle_name = "reply_demo_circle";
let script_to_run = "let x = 40; x + 2"; // Simple script
info!("Starting Dedicated Reply Queue Demo...");
// 1. Create a Rhai Engine for the worker
let engine = Engine::new();
// 2. Setup shutdown channel for the worker
let (shutdown_tx, shutdown_rx) = mpsc::channel::<()>(1);
// 3. Spawn the worker
info!("Spawning worker for circle: {}", circle_name);
let worker_handle = spawn_rhai_worker(
0, // circle_id (can be arbitrary for this demo)
circle_name.to_string(),
engine,
redis_url.to_string(),
shutdown_rx,
false, // preserve_tasks
);
// Give the worker a moment to start up and connect (optional, but good for demo)
tokio::time::sleep(Duration::from_millis(500)).await;
// 4. Create RhaiClient
info!("Creating RhaiClient...");
let client = match RhaiClient::new(redis_url) {
Ok(c) => c,
Err(e) => {
error!("Failed to create RhaiClient: {}", e);
// Attempt to shutdown worker before exiting
let _ = shutdown_tx.send(()).await;
let _ = worker_handle.await;
// Explicitly cast the error to the trait object to satisfy the return type
return Err(Box::new(e) as Box<dyn std::error::Error>);
}
};
info!("RhaiClient created.");
// 5. Submit script and await result using the new mechanism
let task_timeout = Duration::from_secs(10);
let task_id = Uuid::new_v4().to_string(); // Generate a unique task_id
info!(
"Submitting script to circle '{}' with task_id '{}' and awaiting result...",
circle_name, task_id
);
info!("Script: {}", script_to_run);
match client
.submit_script_and_await_result(
circle_name,
task_id.clone(), // Pass the generated task_id
script_to_run.to_string(),
task_timeout,
None, // public_key
)
.await
{
Ok(details) => {
info!("Task {} completed successfully!", details.task_id);
debug!("Full Task Details: {:#?}", details);
// The task_id is now part of the returned RhaiTaskDetails struct.
info!(
"Received details for task_id: {}, script: {}",
details.task_id, details.script
);
info!("Status: {}", details.status);
if let Some(output) = details.output {
info!("Output: {}", output); // Expected: 42
assert_eq!(output, "42");
} else {
error!("Expected output, but got None.");
}
if let Some(error_msg) = details.error {
error!("Error: {}", error_msg);
}
}
Err(e) => {
error!("An error occurred while awaiting task result: {}", e);
// The specific error can be inspected if needed, e.g., for timeout
if let RhaiClientError::Timeout(returned_task_id) = e {
// Note: 'task_id' here is the one from the error, which should match the one we sent.
info!("Task {} timed out.", returned_task_id);
info!("Task {} timed out.", task_id);
}
}
}
// 6. Shutdown the worker
info!("Sending shutdown signal to worker...");
if shutdown_tx.send(()).await.is_err() {
error!("Failed to send shutdown signal to worker. It might have already exited.");
}
info!("Waiting for worker to complete...");
match worker_handle.await {
Ok(Ok(_)) => info!("Worker exited successfully."),
Ok(Err(e)) => error!("Worker exited with an error: {}", e),
Err(e) => error!("Worker task panicked or was cancelled: {}", e),
}
info!("Dedicated Reply Queue Demo finished.");
Ok(())
}