ActorRef.Ask might be a code smell
Ask operator on an
IActorRef allows you to send a message to an actor or actor selection and then await for a response.
This is useful if you want to design some sort of workflow that send queries to one or more actors.
However, this might be a sign of bad design, because when designing a reactive system, you want information to flow in your direction, you should not need to request the information.
So if you find yourself designing actors that are
Ask‘ing for information, this could be sign that your actor should instead be subscribing to events from the source that you are
a Pull based design
For example, let’s say that we are designing a game;
When the player enters a room, we need to know what other players and objects that are present in this room.
We could design this as a query, where the player actor asks the room; “what objects are in here?” and the room could reply to that request.
This is absolutely a viable design, but you might end up designing a lot of complex asynchronous workflows.
- Ask the room what objects are present
- Ask each of the objects what their name (or other state) is
- Aggregate the result from all the objects in the room
- Present the result to the player
This is a fairly complex flow of events.
You need to have some sort of aggregator that can query and collect the responses for all the objects in the room.
And you also need to be able to compose asynchronous callbacks that make up the entire workflow.
Another problem with this design could be performance, when you issue an
Ask to some actor, Akka.NET (and Akka) will spin up a temporary actor that will handle the response message.
Creating actors is fairly fast and cheap, but it is no way near as fast and cheap as just sending plain a message.
a Push based design
A better approach is to make our game push based.
Whenever something or someone enters a room, the room is notified of this and add the incoming object to its own state of contained objects.
At the same time, the room can notify all of the objects it already know about that there is now a new object present in the room.
containedObjects.ForEach(obj => obj.Tell(new AddedContent(incomingObject)))
This will make all the other objects aware of the incoming object, you can also include state like object name.
The incoming object could also be notified by the room where the room tells the incoming object what other objects are already present in the room.
This way, no one needs to ask anyone for information, information is pushed your way when others react to state changes.
The workflow needed to present what other objects are already inside a room would now be something like:
EnteredRoomevent, read the
PresentObjectsproperty of the event
- read the
Nameproperty from each object
- present the names to the user.
None of the above steps require any sort of asynchronous workflow, it is just logic processing data from a message.
This could greatly simplify the design of some actor, instead of trying to spin up and await for some complext flow of messages, you simply react to incoming messages.
There are of course valid cases where you might want to request information, for example see this blog post about the Work Pulling Pattern
You need to decide from a case to case basis how information flow in your system, but you should be aware that if you are using a lot of
Ask, it might just be that you are still stuck in a Request/Response mindset.