Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

Actor Example

This example demonstrates the Dapr actor framework. To author an actor,

  1. 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 an impl IntoResponse. Use the DaprJson extractor 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
    }
  2. Implement the Actor trait. This trait exposes the following methods:

    • on_activate - Called when an actor is activated on a host
    • on_deactivate - Called when an actor is deactivated on a host
    • on_reminder - Called when a reminder is received from the Dapr sidecar
    • on_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(())
        }
    }
  3. An actor host requires an Http server to receive callbacks from the Dapr sidecar. The DaprHttpServer object implements this functionality and also encapsulates the actor runtime to service any hosted actors. Use the register_actor method to register an actor type to be serviced, this method takes an ActorTypeRegistration which 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?;

Running

Before you run the example make sure local redis state store is running by executing:

docker ps
  1. To run the example we need to first build the examples using the following command:
cargo build --examples
  1. Run this example (using the multi-app run):
dapr run -f .

What the multi-run app will achieve:

  1. 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
  1. Start actor client:
dapr run --app-id actor-client --dapr-grpc-port 3502 -- cargo run --example actors-client