Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iii-hq/sdk/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The invocation API allows you to call functions registered by other workers. All invocation methods automatically propagate trace context when the otel feature is enabled.

Calling Functions

call

Call a function and wait for the result (with default 30-second timeout).
pub async fn call(
    &self,
    function_id: &str,
    data: impl serde::Serialize,
) -> Result<Value, IIIError>
function_id
&str
required
ID of the function to call
data
impl serde::Serialize
required
Input data to pass to the function (will be serialized to JSON)
Value
Result<Value, IIIError>
The function’s return value, or an error if the call fails or times out
Example:
use iii_sdk::III;
use serde_json::json;

let iii = III::new("ws://localhost:49134");
iii.connect().await?;

let result = iii.call("user.get", json!({
    "id": "user-123"
})).await?;

println!("User: {}", result);

call_with_timeout

Call a function with a custom timeout.
pub async fn call_with_timeout(
    &self,
    function_id: &str,
    data: Value,
    timeout: Duration,
) -> Result<Value, IIIError>
function_id
&str
required
ID of the function to call
data
Value
required
Input data as a serde_json::Value
timeout
Duration
required
Maximum time to wait for a response
Value
Result<Value, IIIError>
The function’s return value, or IIIError::Timeout if the timeout is exceeded
Example:
use std::time::Duration;
use serde_json::json;

// Call with 5-second timeout
let result = iii.call_with_timeout(
    "long_running_task",
    json!({ "task": "process" }),
    Duration::from_secs(5)
).await?;

call_void

Call a function without waiting for a response (fire-and-forget).
pub fn call_void<TInput>(
    &self,
    function_id: &str,
    data: TInput,
) -> Result<(), IIIError>
where
    TInput: Serialize
function_id
&str
required
ID of the function to call
data
TInput
required
Input data to pass to the function
()
Result<(), IIIError>
Returns immediately after sending the invocation (does not wait for result)
Example:
use serde_json::json;

// Fire-and-forget notification
iii.call_void("notifications.send", json!({
    "user_id": "user-123",
    "message": "Task completed"
}))?;

println!("Notification sent (not waiting for result)");

Legacy Aliases

The SDK also provides trigger, trigger_with_timeout, and trigger_void methods that are aliases for the call methods:
pub async fn trigger(&self, function_id: &str, data: impl serde::Serialize) -> Result<Value, IIIError>
pub async fn trigger_with_timeout(&self, function_id: &str, data: Value, timeout: Duration) -> Result<Value, IIIError>
pub fn trigger_void<TInput>(&self, function_id: &str, data: TInput) -> Result<(), IIIError>
These are functionally identical to call, call_with_timeout, and call_void.

Error Handling

Error Types

Function calls can fail with these errors:
pub enum IIIError {
    NotConnected,           // Client is not connected to engine
    Timeout,                // Call exceeded timeout duration
    Remote {                // Function returned an error
        code: String,
        message: String,
    },
    Handler(String),        // Function handler panicked or failed
    Serde(String),          // Serialization/deserialization error
    WebSocket(String),      // WebSocket communication error
}

Handling Errors

Example:
use iii_sdk::IIIError;
use serde_json::json;

match iii.call("user.delete", json!({ "id": "user-123" })).await {
    Ok(result) => {
        println!("User deleted: {}", result);
    }
    Err(IIIError::Timeout) => {
        eprintln!("Request timed out");
    }
    Err(IIIError::Remote { code, message }) => {
        eprintln!("Remote error {}: {}", code, message);
    }
    Err(IIIError::NotConnected) => {
        eprintln!("Not connected to engine");
    }
    Err(e) => {
        eprintln!("Error: {}", e);
    }
}

Trace Context Propagation

When the otel feature is enabled, trace context is automatically propagated with function calls:
#[cfg(feature = "otel")]
{
    use iii_sdk::{III, with_span, SpanKind};
    use serde_json::json;
    
    let iii = III::new("ws://localhost:49134");
    iii.connect().await?;
    
    // Create a parent span
    let result = with_span(
        "process_order",
        None,
        Some(SpanKind::Internal),
        || async {
            // This call will be a child span of "process_order"
            let user = iii.call("user.get", json!({ "id": "user-123" })).await?;
            
            // This call will also be a child span
            let order = iii.call("order.create", json!({
                "user": user,
                "items": []
            })).await?;
            
            Ok(order)
        }
    ).await?;
}
The SDK automatically:
  • Injects W3C traceparent and baggage headers into outbound calls
  • Extracts these headers from inbound invocations
  • Creates parent-child span relationships across function boundaries

Calling Engine Functions

The III Engine provides built-in functions:

List Functions

let result = iii.call("engine::functions::list", json!({})).await?;
let functions = result.get("functions").unwrap();
Or use the convenience method:
let functions = iii.list_functions().await?;

List Workers

let result = iii.call("engine::workers::list", json!({})).await?;
let workers = result.get("workers").unwrap();
Or use the convenience method:
let workers = iii.list_workers().await?;

Register Worker Metadata

use iii_sdk::WorkerMetadata;

let metadata = WorkerMetadata {
    runtime: "rust".to_string(),
    version: "0.4.1".to_string(),
    name: "my-worker".to_string(),
    os: "linux".to_string(),
    telemetry: None,
};

iii.call_void("engine::workers::register", metadata)?;
Worker metadata is automatically registered when you call connect(), so you typically don’t need to call this manually.

Create Channel

let result = iii.call(
    "engine::channels::create",
    json!({ "buffer_size": 1000 })
).await?;
Or use the convenience method:
let channel = iii.create_channel(Some(1000)).await?;

Typed Invocations

For type-safe function calls, define request and response types:
use serde::{Deserialize, Serialize};

#[derive(Serialize)]
struct CreateUserRequest {
    name: String,
    email: String,
}

#[derive(Deserialize)]
struct CreateUserResponse {
    id: String,
    name: String,
}

let request = CreateUserRequest {
    name: "Alice".to_string(),
    email: "alice@example.com".to_string(),
};

let result = iii.call("user.create", request).await?;
let response: CreateUserResponse = serde_json::from_value(result)?;

println!("Created user: {} ({})", response.name, response.id);

See Also

Build docs developers (and LLMs) love