Expand description
§Restate Rust SDK
Restate is a system for easily building resilient applications. This crate is the Restate SDK for writing Restate services using Rust.
§New to Restate?
If you are new to Restate, we recommend the following resources:
- Learn about the concepts of Restate
- Use cases:
- Quickstart
- Do the Tour of Restate to try out the APIs
§Features
Have a look at the following SDK capabilities:
- SDK Overview: Overview of the SDK and how to implement services, virtual objects, and workflows.
- Configuration: Configure services, objects, workflows and their handlers — timeouts, retention, private-ness and the invocation retry policy — via attribute arguments.
- Service Communication: Durable RPC and messaging between services (optionally with a delay).
- Journaling Results: Persist results in Restate’s log to avoid re-execution on retries
- State: read and write: Store and retrieve state in Restate’s key-value store
- Scheduling & Timers: Let a handler pause for a certain amount of time. Restate durably tracks the timer across failures.
- Awakeables: Durable Futures to wait for events and the completion of external tasks.
- Signals: Named durable promises scoped to an invocation, for communication between invocations.
- Error Handling: Restate retries failures infinitely. Use
TerminalErrorto stop retries. - Serialization: The SDK serializes results to send them to the Server. Includes Schema Generation and payload metadata for documentation & discovery.
- Serving: Start an HTTP server to expose services.
§SDK Overview
The Restate Rust SDK lets you implement durable handlers. Handlers can be part of three types of services:
- Services: a collection of durable handlers
- Virtual Objects: an object consists of a collection of durable handlers and isolated K/V state. Virtual Objects are useful for modeling stateful entities, where at most one handler can run at a time per object.
- Workflows: Workflows have a
runhandler that executes exactly once per workflow instance, and executes a set of steps durably. Workflows can have other handlers that can be called multiple times and interact with the workflow.
§Services
Services and their handlers are defined as follows:
// The prelude contains all the imports you need to get started
use restate_sdk::prelude::*;
// Define the service by annotating an impl block
struct MyService;
#[restate_sdk::service]
impl MyService {
#[handler]
async fn my_handler(&self, ctx: Context<'_>, greeting: String) -> Result<String, HandlerError> {
Ok(format!("{greeting}!"))
}
}
// Start the HTTP server to expose services
#[tokio::main]
async fn main() {
HttpServer::new(Endpoint::builder().bind(MyService).build())
.listen_and_serve("0.0.0.0:9080".parse().unwrap())
.await;
}- Define a service by putting the
#[restate_sdk::service]macro on animplblock of astruct, and annotate each handler with#[handler].- Handlers take
&self, aContext, and optionally one input parameter, and return aResult. - The type of the input parameter of the handler needs to implement
SerializeandDeserialize. Seecrate::serde. - The Result contains the return value or a
HandlerError, which can be aTerminalErroror any other Rust’sstd::error::Error. - The service handler can now be called at
<RESTATE_INGRESS_URL>/MyService/my_handler. You can optionally override the handler name used via#[handler(name = "myHandler")], and the service name via#[restate_sdk::service(name = "MyService")]. More details on handler invocations can be found in the docs.
- Handlers take
- Store dependencies (e.g. clients, config) as fields on the
structand access them via&self. The struct is shared (behind anArc) across all concurrent invocations, so use interior mutability (e.g. aMutexor atomics) for any mutable state. - The parameter after
&selfis always aContextto interact with Restate. The SDK stores the actions you do on the context in the Restate journal to make them durable. - Finally, create an HTTP endpoint and bind the service(s) to it — pass the value directly to
bind, no.serve()needed. Listen on the specified port (here 9080) for connections and requests.
§Virtual Objects
Virtual Objects and their handlers are defined similarly to services, with the following differences:
use restate_sdk::prelude::*;
pub struct MyVirtualObject;
#[restate_sdk::object]
impl MyVirtualObject {
#[handler]
async fn my_handler(
&self,
ctx: ObjectContext<'_>,
greeting: String,
) -> Result<String, HandlerError> {
Ok(format!("{} {}", greeting, ctx.key()))
}
#[handler]
async fn my_concurrent_handler(
&self,
ctx: SharedObjectContext<'_>,
greeting: String,
) -> Result<String, HandlerError> {
Ok(format!("{} {}", greeting, ctx.key()))
}
}
#[tokio::main]
async fn main() {
HttpServer::new(Endpoint::builder().bind(MyVirtualObject).build())
.listen_and_serve("0.0.0.0:9080".parse().unwrap())
.await;
}- Specify that you want to create a Virtual Object by putting the
#[restate_sdk::object]macro on theimplblock. - The context after
&selfmust be theObjectContextparameter. Handlers with theObjectContextparameter can write to the K/V state store. Only one handler can be active at a time per object, to ensure consistency. - You can retrieve the key of the object you are in via [
ObjectContext.key]. - If you want to have a handler that executes concurrently to the others and doesn’t have write access to the K/V state, use the
SharedObjectContextas its context. The shared/exclusive kind is inferred from the context type. You can use these handlers, for example, to read K/V state and expose it to the outside world, or to interact with the blocking handler and resolve awakeables etc.
§Workflows
Workflows are a special type of Virtual Objects, their definition is similar but with the following differences:
use restate_sdk::prelude::*;
pub struct MyWorkflow;
#[restate_sdk::workflow]
impl MyWorkflow {
#[handler]
async fn run(&self, ctx: WorkflowContext<'_>, req: String) -> Result<String, HandlerError> {
// implement workflow logic here
Ok(String::from("success"))
}
#[handler]
async fn interact_with_workflow(&self, ctx: SharedWorkflowContext<'_>) -> Result<(), HandlerError> {
// implement interaction logic here
// e.g. resolve a promise that the workflow is waiting on
Ok(())
}
}
#[tokio::main]
async fn main() {
HttpServer::new(Endpoint::builder().bind(MyWorkflow).build())
.listen_and_serve("0.0.0.0:9080".parse().unwrap())
.await;
}- Specify that you want to create a Workflow by putting the
#[restate_sdk::workflow]macro on theimplblock. - The workflow needs to have a
runhandler. - The context of the
runhandler must be theWorkflowContextparameter. TheWorkflowContextparameter is used to interact with Restate. Therunhandler executes exactly once per workflow instance. - The other handlers of the workflow are used to interact with the workflow: either query it, or signal it.
They use the
SharedWorkflowContextto interact with the SDK. These handlers can run concurrently with the run handler and can still be called after the run handler has finished. - Have a look at the workflow docs to learn more.
Learn more about each service type here:
§Logging
This crate uses the tracing crate to emit logs, so you’ll need to configure a tracing subscriber to get logs. For example, to configure console logging using tracing_subscriber::fmt:
#[tokio::main]
async fn main() {
//! To enable logging
tracing_subscriber::fmt::init();
// Start http server etc...
}You can filter logs when a handler is being replayed configuring the filter::ReplayAwareFilter.
For more information about tracing and logging, have a look at the tracing subscriber doc.
Next, have a look at the other SDK features.
Re-exports§
Modules§
- configuration
- Configuring services and handlers
- context
- Types exposing Restate functionalities to service handlers.
- discovery
- This module contains the generated data structures from the service protocol manifest schema.
- endpoint
- errors
- Error Handling
- filter
- Replay aware tracing filter.
- http_
server - Serving
- hyper
- Hyper integration.
- prelude
- Prelude contains all the useful imports you need to get started with Restate.
- serde
- Serialization
- service
Macros§
- select
- Select macro, alike tokio::select: