| Crates.io | runtara-sdk-macros |
| lib.rs | runtara-sdk-macros |
| version | 1.4.1 |
| created_at | 2025-12-17 14:06:56.223126+00 |
| updated_at | 2026-01-10 20:11:28.968484+00 |
| description | Proc macros for runtara-sdk (#[durable] attribute) |
| homepage | |
| repository | https://github.com/runtara/runtara |
| max_upload_size | |
| id | 1990307 |
| size | 37,858 |
Procedural macros for runtara-sdk, providing the #[durable] attribute for transparent checkpoint-based caching.
This crate provides the #[durable] macro that wraps async functions with automatic checkpointing. When a durable function is called:
This enables crash-resilient workflows where expensive operations (API calls, database queries, computations) are only performed once.
Add to your Cargo.toml:
[dependencies]
runtara-sdk-macros = "1.0"
runtara-sdk = "1.0" # Required for runtime support
Or use runtara-sdk directly, which re-exports this crate:
[dependencies]
runtara-sdk = "1.0"
use runtara_sdk_macros::durable;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct UserData {
id: String,
name: String,
email: String,
}
#[durable]
pub async fn fetch_user(user_id: String) -> Result<UserData, Box<dyn std::error::Error>> {
// This HTTP request only happens once per unique user_id
// On subsequent calls or after crash recovery, the cached result is returned
let response = reqwest::get(&format!("https://api.example.com/users/{}", user_id))
.await?
.json::<UserData>()
.await?;
Ok(response)
}
The checkpoint key includes all serializable arguments:
#[durable]
pub async fn process_order(
order_id: String,
customer_id: String,
amount: f64,
) -> Result<Receipt, OrderError> {
// Checkpoint key: "process_order:order_id:customer_id:amount"
// Same arguments = same cached result
process_payment(order_id, customer_id, amount).await
}
Arguments must implement Serialize, return type must implement Serialize + DeserializeOwned:
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct OrderInput {
items: Vec<String>,
shipping_address: String,
}
#[derive(Serialize, Deserialize)]
struct OrderOutput {
order_id: String,
total: f64,
estimated_delivery: String,
}
#[durable]
pub async fn create_order(input: OrderInput) -> Result<OrderOutput, OrderError> {
// Complex input types work as long as they implement Serialize
submit_order_to_backend(input).await
}
For a function to use #[durable]:
async fnResult<T, E>T must implement Serialize + DeserializeOwnedSerializeruntara_sdk::register_sdk() before calling durable functionsThe macro expands your function to:
// Original
#[durable]
pub async fn fetch_data(id: String) -> Result<Data, Error> {
expensive_operation(id).await
}
// Expanded (simplified)
pub async fn fetch_data(id: String) -> Result<Data, Error> {
let checkpoint_key = format!("fetch_data:{}", serde_json::to_string(&id)?);
if let Some(cached) = runtara_sdk::get_checkpoint(&checkpoint_key).await? {
return Ok(serde_json::from_slice(&cached)?);
}
let result = expensive_operation(id).await?;
runtara_sdk::save_checkpoint(&checkpoint_key, &serde_json::to_vec(&result)?).await?;
Ok(result)
}
runtara-sdk - Main SDK that uses these macrosThis project is licensed under AGPL-3.0-or-later.