This example demonstrates the Dapr actor framework. To author an actor,
-
Create a struc decorated with the
#[dapr::actor]macro to house your custom actor methods that map to Axum handlers, use Axum extractors to access the incoming request and return animpl IntoResponse. Use theDaprJsonextractor to deserialize the request from Json coming from a Dapr sidecar.#[dapr::actor] struct MyActor { id: String, client: ActorContextClient } #[derive(Serialize, Deserialize)] pub struct MyRequest { pub name: String, } #[derive(Serialize, Deserialize)] pub struct MyResponse { pub available: bool, } impl MyActor { fn do_stuff(&self, DaprJson(data): DaprJson<MyRequest>) -> Json<MyResponse> { println!("doing stuff with {}", data.name); Json(MyResponse { available: true }) } }
There are many ways to write your actor method signature, using Axum handlers, but you also have access to the actor instance via
self. Here is a super simple example:pub async fn method_2(&self) -> impl IntoResponse { StatusCode::OK }
-
Implement the
Actortrait. This trait exposes the following methods:on_activate- Called when an actor is activated on a hoston_deactivate- Called when an actor is deactivated on a hoston_reminder- Called when a reminder is received from the Dapr sidecaron_timer- Called when a timer is received from the Dapr sidecar
#[async_trait] impl Actor for MyActor { async fn on_activate(&self) -> Result<(), ActorError> { println!("on_activate {}", self.id); Ok(()) } async fn on_deactivate(&self) -> Result<(), ActorError> { println!("on_deactivate"); Ok(()) } }
-
An actor host requires an Http server to receive callbacks from the Dapr sidecar. The
DaprHttpServerobject implements this functionality and also encapsulates the actor runtime to service any hosted actors. Use theregister_actormethod to register an actor type to be serviced, this method takes anActorTypeRegistrationwhich specifies- The actor type name (used by Actor clients), and concrete struct
- A factory to construct a new instance of that actor type when one is required to be activated by the runtime. The parameters passed to the factory will be the actor type, actor ID, and a Dapr client for managing state, timers and reminders for the actor.
- The methods that you would like to expose to external clients.
let mut dapr_server = dapr::server::DaprHttpServer::new(); dapr_server.register_actor(ActorTypeRegistration::new::<MyActor>("MyActor", Box::new(|actor_type, id, client| Arc::new(MyActor{ actor_type, id, client }))) .register_method("do_stuff", MyActor::do_stuff) .register_method("do_other_stuff", MyActor::do_other_stuff)); dapr_server.start(None).await?;
Before you run the example make sure local redis state store is running by executing:
docker ps
- To run the example we need to first build the examples using the following command:
cargo build --examples- Run this example (using the multi-app run):
dapr run -f .- Start actor host (expose Http server receiver on port 50051):
dapr run --app-id actor-host --app-protocol http --app-port 50051 -- cargo run --example actors-server- Start actor client:
dapr run --app-id actor-client --dapr-grpc-port 3502 -- cargo run --example actors-client