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 a- RhaiDispatcher. Requires a- caller_idand Redis URL.
- RhaiDispatcher: The main client for interacting with the task system. It's used to create- PlayRequestBuilderinstances.
- 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.
- scriptor- script_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/.