Rhai Client
The rhai-client crate provides a fluent builder-based interface for submitting Rhai scripts to a distributed task execution system over Redis. It enables applications to offload Rhai script execution to one or more worker services and await the results.
Features
- Fluent Builder API: A
RhaiDispatcherBuilderfor easy client configuration and aPlayRequestBuilderfor constructing and submitting script execution requests. - Asynchronous Operations: Built with
tokiofor non-blocking I/O. - Request-Reply Pattern: Submits tasks and awaits results on a dedicated reply queue, eliminating the need for polling.
- Configurable Timeouts: Set timeouts for how long the client should wait for a task to complete.
- Direct-to-Worker-Queue Submission: Tasks are sent to a queue named after the
worker_id, allowing for direct and clear task routing. - Manual Status Check: Provides an option to manually check the status of a task by its ID.
Core Components
RhaiDispatcherBuilder: A builder to construct aRhaiDispatcher. Requires acaller_idand Redis URL.RhaiDispatcher: The main client for interacting with the task system. It's used to createPlayRequestBuilderinstances.PlayRequestBuilder: A fluent builder for creating and dispatching a script execution request. You can set:worker_id: The ID of the worker queue to send the task to.scriptorscript_path: The Rhai script to execute.request_id: An optional unique ID for the request.timeout: How long to wait for a result.
- Submission Methods:
submit(): Submits the request and returns immediately (fire-and-forget).await_response(): Submits the request and waits for the result or a timeout.
RhaiTaskDetails: A struct representing the details of a task, including its script, status (pending,processing,completed,error), output, and error messages.RhaiDispatcherError: An enum for various errors, such as Redis errors, serialization issues, or task timeouts.
How It Works
- A
RhaiDispatcheris created using theRhaiDispatcherBuilder, configured with acaller_idand Redis URL. - A
PlayRequestBuilderis created from the client. - The script,
worker_id, and an optionaltimeoutare configured on the builder. - When
await_response()is called: a. A uniquetask_id(UUID v4) is generated. b. Task details are stored in a Redis hash with a key likerhailib:<task_id>. c. Thetask_idis pushed to the worker's queue, namedrhailib:<worker_id>. d. The client performs a blocking pop (BLPOP) on a dedicated reply queue (rhailib:reply:<task_id>), waiting for the worker to send the result. - A
rhai-workerprocess, listening on therhailib:<worker_id>queue, picks up the task, executes it, and pushes the finalRhaiTaskDetailsto the reply queue. - The client receives the result from the reply queue and returns it to the caller.
Prerequisites
- A running Redis instance accessible by the client and the worker services.
Usage Example
The following example demonstrates how to build a client, submit a script, and wait for the result.
use rhai_dispatcher::{RhaiDispatcherBuilder, RhaiDispatcherError};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
// 1. Build the client
let client = RhaiDispatcherBuilder::new()
.caller_id("my-app-instance-1")
.redis_url("redis://127.0.0.1/")
.build()?;
// 2. Define the script and target worker
let script = r#" "Hello, " + worker_id + "!" "#;
let worker_id = "worker-1";
// 3. Use the PlayRequestBuilder to configure and submit the request
let result = client
.new_play_request()
.worker_id(worker_id)
.script(script)
.timeout(Duration::from_secs(5))
.await_response()
.await;
match result {
Ok(details) => {
log::info!("Task completed successfully!");
log::info!("Status: {}", details.status);
if let Some(output) = details.output {
log::info!("Output: {}", output);
}
}
Err(RhaiDispatcherError::Timeout(task_id)) => {
log::error!("Task {} timed out.", task_id);
}
Err(e) => {
log::error!("An unexpected error occurred: {}", e);
}
}
Ok(())
}
Refer to the examples/ directory for more specific use cases, such as timeout_example.rs which tests the timeout mechanism.
Building and Running Examples
To run an example (e.g., timeout_example):
cd src/client # (or wherever this client's Cargo.toml is)
cargo run --example timeout_example
Ensure a Redis server is running and accessible at redis://127.0.0.1/.