Akka Typed : How to get an ActorRef to a local actor? - akka

I'm porting an existing application from Akka Classic to Akka Typed. Originally you could obtain a reference to an actor using context.actorSelection().resolveOne()
I understand that in Akka Typed this is no longer supported, and that we should be using Receptionist to register actors for discovery by ServiceKey.
However I would like to send messages to a local actor only, a local singleton which is present on every node in the cluster. I had a local path for it but do not have the direct reference to it. This is because it is a health check actor created by the Akka Management system.
From the documentation it appears that registering an actor with the Receptionist for a ServiceKey makes it available to all members of the cluster. Therefore I will receive references to the singleton actors on all nodes if I query for that ServiceKey.
There doesn't seem to be a way to register with the Receptionist only locally, and having these internal refs published out across the cluster seems unnecessarily leaky and violates encapsulation.
It also doesn't seem easy to work out which ref is the local actor from the Listing returned from the Receptionist.
I suppose the ServiceKey used to register could be system specific?
Am I missing an obvious solution here?

In the particular case of Akka Management actors, because that project does not depend on Akka Typed (thus the actor involved is a Classic actor), you can treat your Typed ActorContext as a Classic ActorContext and use the ActorSelection.
From your question, I'm guessing Java (in Scala, implicits make this a little less verbose and perhaps clarify intent):
akka.actor.typed.javadsl.Adapter.toClassic(context).actorSelection(path).resolveOne(timeout)
For the case where one wants to resolve only a Typed local actor, the most effective strategy I've found is to incorporate the resolution functionality into the behavior provided when creating the ActorSystem. The actor which wants to be found will register with the ActorSystem and other actors can ask the ActorSystem for the ActorRef.
One subtlety here is that context.getSystem() gives you an ActorSystem<Void> which extends ActorRef<Void>. You can get around this by calling unsafeUpcast on the ActorSystem, e.g.
// Might not actually be syntactically valid Java, but hopefully the fix to make it
// legal is obvious...
ActorRef<MyActorSystemCommand> systemRef = context.getSystem().unsafeUpcast<MyActorSystemCommand>()
Note that it's pretty important to get the type of messages for the ActorSystem correct: if the ActorSystem's behavior doesn't accept that type of message, the actor system will crash (as far as I know, there's no way to prevent the actor system from shutting down) when you send a message.
An evolution of this approach is to define a local-only receptionist actor which is spawned at ActorSystem startup: actors which wish to interact with this receptionist obtain its ActorRef through the above method and then that actor handles resolution.
Note of course, that in both of these approaches (as with the cluster-aware Receptionist), only actors which explicitly opt-in to being resolved like this are resolvable. This is in keeping with an underlying theme of Akka Typed: putting the actor more in charge of how much it exposes to the outside world.

Related

Is it possible to prioritize (give a priority) to specific Akka's Actor?

I've made my research about Akka Framework,
And I would like to know ;
Is it possible to give a priority to a specific actor?
I mean - actors are working while getting a "let" message from the queue,
Is there an option to let an actor work even when it's not his turn yet to work?
Effectively, yes.
One of the parts of your Actor configuration is which Dispatcher those actors will use. A dispatcher is what connects the actor to the actual threads that will execute the work. (Dispatchers default to ForkJoinPools, but can also be dedicated thread pools or even threads dedicated to a specific actor.)
So the typical way you give an Actor "priority" is to give it a dedicated dispatcher, and thereby dedicated threads. For example, Akka itself does this for its internal messages: they run on a dedicated dispatcher so that even you deploy a bunch of poorly written actors that block the threads, Akka itself can still function.
I put "priority" in quotes, because you aren't guaranteeing a specific order of processing. (There are other ways to do that, but not across Actors.) But you are solving the case where you want specific actors to always have a greater access to resources and/or specific actors to get executed promptly.
(In theory, you could take this even further and create a ThreadPoolExecutor with higher priority threads, and then create a Dispatcher based on that ThreadPoolExecutor. That would truly give OS-level priority to an Actor, but that would only be likely relevant in very unusual circumstances.)
EDIT TO RESPOND TO "do mailboxes and dispatchers are the same" [sic]?
No. Each actor has a mailbox. So sometimes we talk about the behavior of mailboxes when discussing the behavior of actors, as the behavior of the mailbox governs the ordering of the actor's message processing.
But dispatchers are a distinct concept. Actors have a dispatcher, but it is many to one. (i.e. each Actor has one mailbox, but there may be many actors associated with a single dispatcher.)
For example, a real world situation might be:
System actors are processed by the internal dispatcher. To quote the docs "To protect the internal Actors that are spawned by the various Akka modules, a separate internal dispatcher is used by default." i.e. no matter how badly screwed up your own code might be, you can't screw up the heartbeat processing and other system messages because they are running on their own dispatcher, and thus their own threads.
Most actors (millions of them perhaps) are processed by the default dispatcher. Huge numbers of actors, as long as they are well behaved, can be handled with a tiny number of threads. So they might all be configured to use the default dispatcher.
Badly behaved actors (such as those that block) might be configured to be processed by a dedicated "blocking" dispatcher. By isolating blocking dispatchers into a separate dispatcher they don't impact the response time of the default dispatcher.
Although I don't see this often, you might also have a dispatcher for extremely response time sensitive actors that gives them a dedicated thread pool. Or even a "pinned" dispatcher that gives an actor a dedicated thread.
As I mentioned this isn't really "priority", this is "dedicated resources". Because one of the critical aspects of actors is that the are location independent. So if Actor A is on Node A, and Actor B is on Node B, I can't guarantee that Actor A will ALWAYS act first. Because doing so would involve an ASTRONOMINCAL amount of overhead between nodes. All I can reasonably do is give Actor A dedicated resources so that I know that Actor A should always be able to act quickly.
Note that this is what the internal dispatcher does as well. We don't guarantee that heartbeat messages are always processed first, but we do make sure that there are always threads available to process system messages, even if some bad user code has blocked the default dispatcher.

akka and the benefits of at-most-once message semantics

I'm going through this tutorial: https://doc.akka.io/docs/akka/current/typed/guide/tutorial_3.html and don't quite understand when the at-most-once message semantics is preferable, since although we get performance gains, we lose resiliency of messages. It looks like the justification for this trade-off is explained here:
We only want to report success once the order has been actually fully processed and persisted. The only entity that can report success is the application itself, since only it has any understanding of the domain guarantees required. No generalized framework can figure out the specifics of a particular domain and what is considered a success in that domain.
In this particular example, we only want to signal success after a successful database write, where the database acknowledged that the order is now safely stored. For these reasons Akka lifts the responsibilities of guarantees to the application itself, i.e. you have to implement them yourself with the tools that Akka provides. This gives you full control of the guarantees that you want to provide. Now, let’s consider the message ordering that Akka provides to make it easy to reason about application logic.
, but I don't quite understand what it means. Any help in understanding this or some other considerations for this decision is appreciated.
I read this thread RPC semantics what exactly is the purpose which seemed to offer a clear definition of the use cases of at-most-once semantics with payment submission as the example of something you wouldn't want to duplicate. But from the quoted paragraph above, it sounds like the messages would be sent out into the ether with no regard for an ack that confirms success or failure of message delivery. I'm wondering if both descriptions of at-most-once semantics is correct to their respective domains, how to get the behavior in the other stackoverflow thread with an acknowledgement from akka.
All anything that doesn't know about the domain can offer with at-least or exactly-once delivery is that the message has been delivered (a guarantee that the message has been processed is also possible and practical in at least some (but not all) scenarios). This is fine if it's what you want, but conflating this with something higher level (like "order has been durably recorded") is virtually certain to lead to essentially impossible to debug bugs down the road.
At-least-once is quite easy to accomplish in Akka by having messages include a field containing an ActorRef to which to send an ack (or other response) and having the sender resend unacked messages (because it's eminently possible for the ack to get dropped, these retries are what leads to at-least-once). The ask pattern (included with Akka) provides this at a high level: in Akka Typed this is done by specifying an adapter function so that when actor A asks actor B, B can send a message in its protocol and A gets a message in its protocol (avoiding a chicken-and-egg problem); if no response is received in a specified timeframe, the adapter causes a failure message to be sent to actor A which (for at-least-once semantics would dictate that A eventually retry the message). The critical thing to remember is that it's actor B (or its designee: e.g. if B farms the work out to a worker actor, that worker actor can send the acknowledgement to A) that decides whether and when to respond, not Akka.
If doing at-least-once, it's very useful to design the messaging protocol around idempotence: a retry of a successful message doesn't result in a side effect beyond an ack. Idempotence plus at-least-once has been referred to as "effectively-once" and it's a lot easier to implement and lighter-weight than exactly-once.
Akka's docs on interaction patterns describe various messaging patterns in Akka, with a discussion of advantages and disadvantages. Fairly recently, especially when using Akka Cluster and Akka Persistence, there is a fairly heavyweight implementation of reliable delivery: in the maximum reliability mode (using Akka Persistence), because each message sent in this way is persisted to a datastore (e.g. local disk, or cassandra, or...), the latency for a message send is severely increased.

Can we have global state in actor-based systems?

One of the biggest advantages of the actor model is the removal of locking (actors operate independently and serially). Does this mean that we cannot have any shared/global state at all in an actor system (because accessing/updating that will bring in locks)?
In more practical terms, what happens to updates to an entity (e.g. DB) from multiple actors in such a system?
Actor model intended to solve issue with any mutable shared state in another way - actor should encapsulate it. So if you need something to be shared between actors - this should be an actor with this state and protocol to work with it. If you would like to update DB from different actors - extract an actor responsible for this, and provide API or protocol for other actors to update DB. Or make several actors to handle DB updates and route messages between them (Please, see for more details: https://doc.akka.io/docs/akka/current/typed/routers.html)
General approach - think about shared state, as actor shared between actors (via ActorRef) and state API as messages for this actor.
Usually, it is not a preferred way to have a shared/global state in an actor system. A very central idea when working with actors is to not share any mutable state, instead, mutable state is encapsulated inside of the actors as pointed out in the documanetation
Do not pass mutable objects between actors. In order to ensure that,
prefer immutable messages. If the encapsulation of actors is broken by
exposing their mutable state to the outside, you are back in normal
Java concurrency land with all the drawbacks.
Actors are made to be containers for behavior and state, embracing
this means to not routinely send behavior within messages (which may
be tempting using Scala closures). One of the risks is to accidentally
share mutable state between actors, and this violation of the actor
model unfortunately breaks all the properties which make programming
in actors such a nice experience.
Moreover, If one actor needs to know something about the state of another actor it will ask for it using immutable messages and get an immutable reply.One of the key features of Akka actors its their ability to manage state in a thread-safe manner and by having a shared and mutable state, we will violate this property
Usually DB reading operations (CRUD) can be performed directly by any actor.To perform this. make an actor responsible for this, and use it from other actors.
Let me know if it helps!!

Granularity of actors in actor model

My team is debating how granular our actors should be.
As an example, we have an actor that is responsible for deserializing a json string into an object. The argument in favour of making it an actor is that the deserialization can cause errors and actors and their supervision model can be used for control flow.
Is it a good idea to use actors for this and other small tasks?
Yes, it is a good idea to delegate tasks that are routinely prone to failure to child actors which handle that specific task. This pattern is referred to as the Character Actor pattern on the Petabridge blog, but reiterated below in case the link breaks in future.
The Character Actor Pattern is used when an application has some risky but critical operation to execute, but needs to protect critical state contained in other actors and ensure that there are no negative side effects.
It’s often cheaper, faster, and more reliable to simply delegate these risky operations to a purpose-built, but trivially disposable actor whose only job is to carry out the operation successfully or die trying.
These brave, disposable actors are Character Actors.
Character actors can be temporary or long-running actors, but typically they’re designed to carry out only one specific type of risky operation. Often times character actors can be re-used throughout an application, belonging to many different types of parents. For example, you may have a utility character actor that handles making external network requests, and is then used by parent actors throughout your application for their own purposes.
Use Cases
The Character Actor pattern is broadly applicable. Use it any time you need to do something risky such as network calls, file I/O, parsing malformed content, and so on. Any of these operations is a good candidate for a character actor.
Character actors are most effective when used to provide protection and fault isolation to some other important type of actor, typically one containing some important state.
Benefits
There are three key benefits to using the Character Actor Pattern:
Insulates stateful and critical actors from failures and risky operations;
Makes it easy to cleanly introduce retry / backoff / undo semantics specific to each type of risky operation: since you have a character actor specific to each risky task, you have a well-defined place to put retry handling and related operations. These are specific to the task the Character Actor was created for and don’t need to be shared with the rest of your actors, meaning that the pattern…
Reduces code by letting the SupervisionStrategy and actor lifecycle do most of the heavy lifting, you don’t need all sorts of exception handling code in your parent actors. Just let it crash, baby.

Is Akka real actor model?

When working with Scala Akka, we still think about blocking IO, and try to avoid it with patterns, I feel it makes no difference from using threads. Implicitly async IO is a huge differentiator, Erlang and Go provide it at language level, while Scala Akka does not. I feel Scala Akka is not real actor model.
There's a popular blog post Don't use Actors for concurrency, but it's not really a problem of actor model, it's purely a problem of Akka.
Akka implements the Actor Model as specified by Carl Hewitt et al in 1973: an actor can upon reception of a message
send a finite number of messages to actors it knows
create a finite number of actors
determine the behavior to be applied to the next message
Nowhere does this say anything about how exactly I/O is supposed to be handled. Translating blocking method calls into actor-suspending method calls automatically is on the other hand a violation of the model: actors only act upon messages, nothing else, and declaring some arbitrary method calls to prevent that from happening for some (possibly unbounded) time is not part of the model.
Akka provides IO facilities for network operations that are presented in an Actor Model fashion by exposing an ActorRef that commands can be sent to and results can be received from. Akka Streams includes asynchronous consumption and production of data from and to I/O channels.
I hope this explains why my overall answer is that the premise of the question is flawed.
The premise of your question is inaccurate
("...Scala Akka does not."). From the akka documentation:
Actors give you:
Simple and high-level abstractions for concurrency and parallelism.
Asynchronous, non-blocking and highly performant event-driven
programming model. Very lightweight event-driven processes (several
million actors per GB of heap memory).
A basic example of asynchronous message passing to an Actor:
val actorSystem = ActorSystem()
val actorRef = actorSystem actorOf Props[SomeActor]
val message = ??? //some message value
actorRef ! message //asynchronous message passing
In fact, akka exceeds the original Actor Model specification with the ability to lookup Actors by name.
For IO specifically, akka offers many non-blocking solutions:
TCP
HTTP
Streaming File IO
Granted, Scala the language does not have an embedded Actor Model. But it provides Futures and parallel collections for concurrent computation.
The gist of the blog you quoted was that Futures are much better for concurrent computation (which I agree with), while Actors are for maintaining state. It wasn't claiming that Actors are incapable of concurrency.
Plus, akka is not just Actors. There are Agents, finite state machines, akka streams (implementing the reactive manifesto), and the akka-http library.