Best practices question:
Should an Akka message type (case class) be always only sent by a single type of actor and received only by a single type of actor?
Example:
Three actor types: MainSender, MainReceiver, Worker
MainSender sends a message DoSomething(work) to MainReceiver.
MainReceiver forwards the DoSomething(work) message to Worker.
Is this the best practice? Or would it be better to define a new case class for the other sender-receiver pair?
MainSender sends a message DoSomething(work) to MainReceiver.
MainReceiver sends a message StartWorking(work) to Worker.
You can totally send the same message to any actor as long as it makes sense in your architecture. It is totally encouraged to reuse your code.
As you suggested, that is exactly what the forward function does.
The same logic goes for Exception: if you want to throw an Exception, you can use an existing one if it fits your needs or create a new one otherwise.
Related
Is it possible to handle multiple message types from a single actor.
For example, assume there is an actor called TradingStrategy that trades stocks. It takes in pricing data pumped in from another Actor. When it decides to place a trade, it sends a message to an another Actor, call it OrderActor, to place a trade. But the TradingStrategy Actor is interested in knowing whether or not the order placed was successful or rejected, etc... because it may change its strategy based on the results from the place order action. In this example, it seems the TradingStrategy needs to handle messages for pricing updates AND order updates. Is this possible with Akka typed? Are there ways to handle this situation?
Here is a code example:
IEXData is the data message.
def apply(orderActor: ActorRef[OrderCommand]): Behavior[IEXData] = Behaviors.setup { context =>
new SimpleTradingStrategy(context, brokerActor)
}
}
class SimpleTradingStrategy(
context: ActorContext[IEXData],
orderActor: ActorRef[OrderCommand],
ticker: Ticker = "spy"
) extends AbstractBehavior[IEXData](context) {
TradingStrategy's protocol would have to include messages indicating order updates. A TradingStrategy actor can register a message adapter which will translate the messages sent by the order actor into TradingStrategy's protocol: the TradingStrategy can present the "virtual" ActorRef returned by the message adapter to the order actor without the order actor knowing that its a TradingStrategy.
I create an actor A. When I send a message to A, the receive method tries to create an actor B. When I run a piece of code that calls:
context.system.actorOf(Props[B], "B")
I get an exception:
InvalidActorNameException: actor name [B] is not unique!
Do you have any idea why this is happening?
Actor paths (part of which is the name that you pass to system.actorOf or context.actorOf, if you use the variants of actorOf that take a name) must be unique in an actor system. You're probably sending more than one message to actor A: every time actor A receives this message, it tries to create a top-level actor B with the name "B". Either drop the name altogether...
context.system.actorOf(Props[B])
...or add a unique identifier to the name. For example:
val uuid = java.util.UUID.randomUUID.toString
context.system.actorOf(Props[B], s"B-${uuid}")
As a side note, top-level actors (i.e., actors created via system.actorOf) should be made sparingly, as the documentation advises:
Top-level actors are the innermost part of your Error Kernel, so create them sparingly and prefer truly hierarchical systems. This has benefits with respect to fault-handling (both considering the granularity of configuration and the performance) and it also reduces the strain on the guardian actor, which is a single point of contention if over-used.
If your intent is to create an actor B as a child of actor A every time the latter receives a message, then use context.actorOf.
I have a very simple question, but I haven't found anything on the Internet (maybe I don't know how to search for it).
If I deploy an actor (actorSystem.actorOf ...) and I send a message to it immediately, if the Actor hasn't been deployed yet will the messages be enqueued in a "special" queue or will the messages be sent to DeadLetters?
Have a look at the bottom of the mailbox documentation. Your guess is correct that messages are stored in a special queue until the mailbox is ready.
In order to make system.actorOf both synchronous and non-blocking while keeping the return type ActorRef (and the semantics that the returned ref is fully functional), special handling takes place for this case. Behind the scenes, a hollow kind of actor reference is constructed, which is sent to the system’s guardian actor who actually creates the actor and its context and puts those inside the reference. Until that has happened, messages sent to the ActorRef will be queued locally, and only upon swapping the real filling in will they be transferred into the real mailbox.
Actor mailboxes
I would like to use an actor to synchronize access to a pool of objects. The actor would manage the objects in the pool including their state (busy v.s. free to allocate). When asked by non-actor code, it would return an object from the pool once available. Thus the calling code has an abstraction for obtaining an object to work with.
To get this kind of abstraction, I need the actor to be able to respond to its message senders' ask messages with the object the actor is allocating to them. Can this be accomplished and would it be resource intensive to pass a whole object via a message?
There is nothing wrong in returning future that will be completed later, by actor.
Keep an eye on this matter, however: will you complete the future with some mutable internal actor state or not?
If the answer is no - it is ok and there is nothing you should worry about.
If the answer is yes - you'll have to take care of synchronization, since actor/external code may mutate this state in different threads (which, kind of defeats the purpose of using actors).
Otherwise it is legit.
BTW, this is not something that is specific to futures only. You have to follow this for any message you send from actor.
UPDATE: extending my answer to address OP's comment.
Question was primarily about returning an object that's not an actor, from an actor, not just about the scenario... not sure if this answer relates to just that... an object can be much heavier than just a "regular" message... unless Akka passes a message in a way equivalent to a reference / interning.
There is no special requirements about "heaviness" of the message in akka and in general it can be any object (you can infer this from the fact that Any is used for the type of the message instead of some akka-defined message class/trait with set of defined limitations).
Of course, you have to treat specially situations when messages should be persisted or sent to remote host, but this is kind of special case. In this scenario you have to ensure that serialization is handled properly.
Anyway, if the message (object) does not leave boundaries of the same jvm - it is ok for object to hold any amount of state.
I'm new to the Akka framework and I'm building an HTTP server application on top of Netty + Akka.
My idea so far is to create an actor for each type of request. E.g. I would have an actor for a POST to /my-resource and another actor for a GET to /my-resource.
Where I'm confused is how I should go about actor creation? Should I:
Create a new actor for every request (by this I mean for every request should I do a TypedActor.newInstance() of the appropriate actor)? How expensive is it to create a new actor?
Create one instance of each actor on server start up and use that actor instance for every request? I've read that an actor can only process one message at a time, so couldn't this be a bottle neck?
Do something else?
Thanks for any feedback.
Well, you create an Actor for each instance of mutable state that you want to manage.
In your case, that might be just one actor if my-resource is a single object and you want to treat each request serially - that easily ensures that you only return consistent states between modifications.
If (more likely) you manage multiple resources, one actor per resource instance is usually ideal unless you run into many thousands of resources. While you can also run per-request actors, you'll end up with a strange design if you don't think about the state those requests are accessing - e.g. if you just create one Actor per POST request, you'll find yourself worrying how to keep them from concurrently modifying the same resource, which is a clear indication that you've defined your actors wrongly.
I usually have fairly trivial request/reply actors whose main purpose it is to abstract the communication with external systems. Their communication with the "instance" actors is then normally limited to one request/response pair to perform the actual action.
If you are using Akka, you can create an actor per request. Akka is extremely slim on resources and you can create literarily millions of actors on an pretty ordinary JVM heap. Also, they will only consume cpu/stack/threads when they actually do something.
A year ago I made a comparison between the resource consumption of the thread-based and event-based standard actors. And Akka is even better than the event-base.
One of the big points of Akka in my opinion is that it allows you to design your system as "one actor per usage" where earlier actor systems often forced you to do "use only actors for shared services" due to resource overhead.
I would recommend that you go for option 1.
Options 1) or 2) have both their drawbacks. So then, let's use options 3) Routing (Akka 2.0+)
Router is an element which act as a load balancer, routing the requests to other Actors which will perform the task needed.
Akka provides different Router implementations with different logic to route a message (for example SmallestMailboxPool or RoundRobinPool).
Every Router may have several children and its task is to supervise their Mailbox to further decide where to route the received message.
//This will create 5 instances of the actor ExampleActor
//managed and supervised by a RoundRobinRouter
ActorRef roundRobinRouter = getContext().actorOf(
Props.create(ExampleActor.class).withRouter(new RoundRobinRouter(5)),"router");
This procedure is well explained in this blog.
It's quite a reasonable option, but whether it's suitable depends on specifics of your request handling.
Yes, of course it could.
For many cases the best thing to do would be to just have one actor responding to every request (or perhaps one actor per type of request), but the only thing this actor does is to forward the task to another actor (or spawn a Future) which will actually do the job.
For scaling up the serial requests handling, add a master actor (Supervisor) which in turn will delegate to the worker actors (Children) (round-robin fashion).