This document describes how to create an Actor(DemoActor) and invoke its methods on the client application.
- The actor interface(demo_actor_interface.py). This contains the interface definition for the actor. Actor interfaces can be defined with any name. The interface defines the actor contract that is shared by the actor implementation and the clients calling the actor. Because client may depend on it, it typically makes sense to define it in an assembly that is separate from the actor implementation.
- The actor service(demo_actor_service.py). This implements FastAPI service that is going to host the actor. It contains the implementation of the actor,
demo_actor.py. An actor implementation is a class that derives from the base typeActorand implements the interfaces defined indemo_actor_interface.py. - The actor service for flask(demo_actor_flask.py). This implements Flask web service that is going to host the actor.
- The actor client(demo_actor_client.py) This contains the implementation of the actor client which calls DemoActor's method defined in Actor Interfaces.
- Actor tests(test_demo_actor.py) This contains actor unit tests using mock actor testing functionality.
You can install dapr SDK package using pip command:
pip3 install -r demo_actor/requirements.txt-
Run Demo Actor service in new terminal window
cd demo_actor dapr run --app-id demo-actor --app-port 3000 -- uvicorn --port 3000 demo_actor_service:appExpected output:
... Activate DemoActor actor! has_value: False INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/GetMyData HTTP/1.1" 200 OK has_value: False INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/GetMyData HTTP/1.1" 200 OK set_my_data: {'data': 'new_data'} INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/SetMyData HTTP/1.1" 200 OK has_value: True INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/GetMyData HTTP/1.1" 200 OK set reminder to True set reminder is done INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/SetReminder HTTP/1.1" 200 OK set_timer to True set_timer is done INFO: 127.0.0.1:50739 - "PUT /actors/DemoActor/1/method/SetTimer HTTP/1.1" 200 OK receive_reminder is called - demo_reminder reminder - b'reminder_state' clear_my_data ...
-
Run Demo client in new terminal window
# Run actor client cd demo_actor dapr run --app-id demo-client -- python3 demo_actor_client.py
Expected output:
... call actor method via proxy.invoke_method() b'null' call actor method using rpc style None Actor reentrancy enabled: True call SetMyData actor method to save the state call GetMyData actor method to get the state {'data': 'new_data', 'ts': datetime.datetime(2020, 11, 13, 0, 38, 36, 163000, tzinfo=tzutc())} Register reminder Register timer waiting for 30 seconds stop reminder stop timer clear actor state
-
Build and push docker image
$ cd examples/demo_actor/demo_actor $ docker build -t [docker registry]/demo_actor:latest . $ docker push [docker registry]/demo_actor:latest $ cd ..
For example, [docker registry] is docker hub account.
-
Follow these steps to create a Redis store.
-
Once your store is created, confirm validate
redis.ymlfile in thedeploydirectory.Note: the
redis.ymluses the secret created bybitmany/redisHelm chat to securely inject the password. -
Apply the
redis.ymlfile:kubectl apply -f ./deploy/redis.ymland observe that your state store was successfully configured!component.dapr.io/statestore configured
-
Update docker image location in
./deploy/demo_actor_client.ymland./deploy/demo_actor_service.yml -
Deploy actor service and clients
kubectl apply -f ./deploy/demo_actor_service.yml kubectl apply -f ./deploy/demo_actor_client.yml -
See logs for actor service and client
Logs for actor service sidecar:
dapr logs -a demoactor -kLogs for actor service app:
kubectl logs -l app="demoactor" -c demoactorLogs for actor client sidecar:
dapr logs -a demoactor-client -kLogs for actor service app:
kubectl logs -l app="demoactor-client" -c demoactor-client
-
Run Tests
cd demo_actor python -m unittest test_demo_actor.pyExpected output (note that the unit test print outputs might not necessarily be in this order - what really matters is that all tests pass anyway):
set_my_data: {'state': 5} has_value: True clear_my_data has_value: False has_value: False set reminder to True set reminder is done set reminder to False set reminder is done set_my_data: {'state': 5} has_value: True ---------------------------------------------------------------------- Ran 5 tests in 0.052s OK