Is passing around ActorRef to other Actors good or bad ? - scala

I'm trying to figure out if my usage of passing Akka ActorRef around to other actors is not an anti-pattern.
I've a few actors in my system. Some are long lived (restClientRouter,publisher) and some die after that they have done the work (geoActor). The short-lived actors need to send messages to the long-lived actors and therefore need their ActorRefs.
//router for a bunch of other actors
val restClientRouter = createRouter(context.system)
//publishers messages to an output message queue
val publisher: ActorRef = context.actorOf(Props(new PublisherActor(host, channel)), name = "pub-actor")
//this actor send a message to the restClientRouter and then sends the response
//to the publisher
val geoActor = context.actorOf(Props(new GeoInferenceActor(restClientRouter, publisher)), name = "geo-inference-actor")
As you can see I'm passing the ActorRefs (restClientRouter and publisher) to the constructor of GeoInferenceActor. Is this okay or not? Is there a better way of doing this ?

There are a couple of good ways to "introduce" actor refs to actor instances that need them.
1) Create the actor with the refs it needs as constructor args (which is what you are doing)
2) Pass in the needed refs with a message after the instance is created
Your solution is perfectly acceptable, and even suggested by Roland Kuhn, the Tech Lead for Akka, in this post:
Akka actor lookup or dependency injection

It is perfectly valid, as stated in the Akka API documentation:
ActorRefs can be freely shared among actors by message passing.
In your case, you are passing them to the constructors, which is absolutely fine and the way it is supposed to be.

Related

Scala Akka how to create a Typed ActorContext in route

I am pretty new in Scala Akka . Say I am spawning a Configuration child actor,
object Configuration {
def apply(): Behavior[ConfigurationMessage] = Behaviors.setup(context => new Configuration(context))
}
Now I need same context ActorContext[ConfigurationMessage] in my HTTP router to do some operation.
How can I create the same ActorContext there
The ActorContext cannot be used outside of the actor it's associated with, including in an HTTP router. Any ActorContext which leaks out of an actor (e.g. by sending it as a message) will, by design, throw an exception and not do anything for most operations if it's used outside of its actor.
The only operations on the ActorContext which could possibly be used outside of the associated actor are:
context.ask and friends can be just as easily replaced with a Future-returning ask on the target RecipientRef with the message send occurring in a foreach callback on the future.
context.executionContext: can just as easily use system.executionContext (which will typically be the same) or by looking up via dispatchers
context.pipeToSelf is probably best done as a send in a foreach callback on the future
context.scheduleOnce is better done using the system scheduler directly
context.self is kind of pointless, as you'd have to have the ActorRef already in order to leak the ActorContext
context.system is likewise pointless, as you already have the system

How does akka update a mutable state? [duplicate]

This question already has an answer here:
Does Akka onReceive method execute concurrently?
(1 answer)
Closed 1 year ago.
I read Akka documentation, but I do not understand:
class MyActor extends Actor {
private var _state = 0
override def receive: Receive = {
case x: Int =>
if (x != _state) {
println(s"---------> fail: ${x} and ${_state}")
}
_state = x + 1
}
}
implicit val system = ActorSystem("my-system")
val ref = system.actorOf(Props[MyActor], "my-actor")
(0 to 10000).foreach { x =>
ref ! x
}
I have a _state variable which is not #volatile and not atomic but at the same time _state is always correct, if I do changes with !-method.
How does Akka protect and update the internal state of actors?
Akka is an implementation of the Actor Model of computation. One of the (arguably the) key guarantees made by the actor model is that an actor only ever processes a single message at a time. Simply by virtue of having _state be private to an actor, you get a concurrency guarantee that's at least as strong as if you had every method of an object be #synchronized, with the added bonus of the ! operation to send a message being non-blocking.
Under the hood, a rough (simplified in a few places, but the broad strokes are accurate) outline of how it works and how the guarantee is enforced is:
Using the Props the ActorSystem constructs an instance of MyActor, places the only JVM reference to that instance inside an ActorCell (I'm told this terminology, as well as that the deep internals of Akka are "the dungeon", is inspired by the early development team for Akka being based in an office in what was previously a jail in Uppsala, Sweden), and keys that ActorCell with my-actor. In the meantime (technically this happens after system.actorOf has already returned the ActorRef), it constructs an ActorRef to allow user code to refer to the actor.
Inside the ActorCell, the receive method is called and the resulting PartialFunction[Any, Unit] (which has a type synonym of Receive) is saved in a field of the ActorCell which corresponds to the actor's behavior.
The ! operation on the ActorRef (at least for a local ActorRef) resolves which dispatcher is responsible for the actor and hands the message to the dispatcher. The dispatcher then enqueues the message into the mailbox of the ActorCell corresponding to my-actor (this is done in a thread-safe way).
If there is no task currently scheduled to process messages from the actor's mailbox, such a task is enqueued to the dispatcher's execution context to dequeue some (configurable) number of messages from the ActorCell's mailbox and process them, one-at-a-time, in a loop. After that loop, if there are more messages to process, another such task will be enqueued. Processing a message consists of passing it to the Receive stored in the ActorCell's behavior field (this mechanism allows the context.become pattern for changing behavior).
It's the last bit that provides the core of the guarantee that only one thread is ever invoking the Receive logic.
This is the Classic model for Akka Actors. If you are just learning actors then you should use Typed Actors because that is the supported model going forwards.
With typed actors, the actor system holds the state for each actor, not the actor itself. When an actor needs to process a message the actor system will pass the current state to the actor. The actor will return the new state back to the actor system when it has finished processing the message.
The typed model avoids all synchronisation issues because it does not use any external state, it only uses the state that is passed to it. And it does not modify any external state, it just returns a modified state value.
If you must use Classic actors then you can implement the same model using context.become rather than a var.

How to name an actor?

The data layer in my web application is comprised of Akka actors. Whenever I need to access data, I invoke the ActorSystem mechanism like so:
val myActor = system.actorOf(Props[MyActor], name = "myactor")
implicit val timeout = Timeout(120 seconds)
val future = myActor ? Request1
val result = Await.result(future, timeout.duration)
I'm using Play, and the ActorSystem variable is obtained through injection:
class MyClass #Inject() (system: ActorSystem)
But I'm getting the following exception saying that the actor name is not unique the second time I access the function, how to fix this? How to name the actor, taking into account that can be used concurrently by more than one thread?
play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution
exception[[InvalidActorNameException: actor name [myactor] is not
unique!]]
** EDIT **
What I'm trying to achieve is something similar to having a container of Entity Beans in the EJB model, where each actor would be an Entity Bean. The difference I'm noticing is that the actors are not created/destroyed automatically as needed.
Depending on your goal, the question may be not how to name an actor, but when to create it. You are creating a new actor every time you need to access some data. I suppose you aren't stopping old actors when they are no longer needed.
You should probably create an actor once (or multiple times if you want a pool of actors, but using different names) and reuse it later by keeping an ActorRef somewhere or using dependency injected actors. You can also use system.actorFor or system.actorSelection (depending on Akka version you're using) if you really need to.
Most of the time you don't even need an explicit ActorRef because you want to reply to a sender of some message.
If you have to create a separate actor each time, then see Wonpyo's answer. In my opinion, though, you could simply use a Future directly instead.
There is a great guide on Actors in the Akka documentation.
Edit:
Since you specified you want each actor to act like a DAO class, I think it should look something like:
// Somewhere in some singleton object (injected as dependency)
val personDao : ActorRef = system.actorOf(Props[PersonDaoActor], name = "personDao")
val fruitDao : ActorRef = system.actorOf(Props[FruitDaoActor], name = "fruitDao")
Then, when you need to access some data:
val johnSmithFuture = personDao ? Get("John Smith")
johnSmithFuture.map {
case Person(name, age) => println(s"${name} ${age}")
}
Alternatively, instead of personDao you can use system.actorFor("personDao") (or system.actorSelection equivalent in Akka 2.4). You can also inject actors directly.
If you want multiple actors to process your messages in parallel you can use routers. Example:
val personDao: ActorRef =
system.actorOf(RoundRobinPool(5).props(Props[PersonDaoActor]), "personDao")
It would create 5 instances of your PersonDaoActor and distribute any messages sent to personDao among those 5 actors, so you could process 5 queries in parallel. If all 5 actors are busy, messages will be queued.
Using Await defeats the purpose of Akka in this case. There are some cases when this is the only option (legacy code, mostly), but using it every time effectively makes your code completely blocking, maybe even single-threaded (depending on your actor code). This is especially true in Play, which is designed to do everything asynchronously, so there's no need to Await.
It may be a good idea to reconsider if actors are really the best solution to your problem. If all you want is parallel execution, then Futures are much simpler. Some people still use actors in such case because they like the abstraction and the simplicity of routing. I found an interesting article describing this in detail: "Don't use Actors for concurrency" (also read the comments for opposing views).
Actor System requires unique name (path) for each actor.
Path has follwing format akka://system#host:port/user/{your-actor-path}
For example
val system = ActorSystem("hello")
val myActor = system.actorOf(Props[MyActor], name ="myactor")
// myActor Path
// "akka://hello/user/myactor" // purely local
// "akka.tcp://hello#ip:port/user/myactor" // remote
and in your code, myActor is created everytime, you make a call.
which makes an actor in the same path everytime.
Thus, Bad solution is to change the code as following
val myActor = system.actorOf(Props[MyActor])
If you don't assign a name to an actor then actor system will assign an random name
and myActor will not have same path for each function call.
But, this is really bad solution, since myActor will not be destructed
(Actor is not terminated by GC)
If you keep calling the function, then your memory will be out of space one day.
So, please DESTRUCT myActor after you done with the function.

Is sending futures in Akka messages OK?

I'm working on implementing a small language to send tasks to execution and control execution flow. After the sending a task to my system, the user gets a future (on which it can call a blocking get() or flatMap() ). My question is: is it OK to send futures in Akka messages?
Example: actor A sends a message Response to actor B and Response contains a future among its fields. Then at some point A will fulfill the promise from which the future was created. After receiving the Response, B can call flatMap() or get() at any time.
I'm asking because Akka messages should be immutable and work even if actors are on different JVMs. I don't see how my example above can work if actors A and B are on different JVMs. Also, are there any problems with my example even if actors are on same JVM?
Something similar is done in the accepted answer in this stackoverflow question. Will this work if actors are on different JVMs?
Without remoting it's possible, but still not advisable. With remoting in play it won't work at all.
If your goal is to have an API that returns Futures, but uses actors as the plumbing underneath, one approach could be that the API creates its own actor internally that it asks, and then returns the future from that ask to the caller. The actor spawned by the API call is guaranteed to be local to the API instance and can communicate with the rest of the actor system via the regular tell/receive mechanism, so that there are no Futures sent as messages.
class MyTaskAPI(actorFactory: ActorRefFactory) {
def doSomething(...): Future[SomethingResult] = {
val taskActor = actorFactory.actorOf(Props[MyTaskActor])
taskActor ? DoSomething(...).mapTo[SomethingResult]
}
}
where MyTaskActor receives the DoSomething, captures the sender, sends out the request for task processince and likely becomes a receiving state for SomethingResult which finally responds to the captured sender and stops itself. This approach creates two actors per request, one explicitly, the MyTaskActor and one implicitly, the handler of the ask, but keeps all state inside of actors.
Alternately, you could use the ActorDSL to create just one actor inline of doSomething and use a captured Promise for completion instead of using ask:
class MyTaskAPI(system: System) {
def doSomething(...): Future[SomethingResult] = {
val p = Promise[SomethingResult]()
val tmpActor = actor(new Act {
become {
case msg:SomethingResult =>
p.success(msg)
self.stop()
}
}
system.actorSelection("user/TaskHandler").tell(DoSomething(...), tmpActor)
p.future
}
}
This approach is a bit off the top of my head and it does use a shared value between the API and the temp actor, which some might consider a smell, but should give an idea how to implement your workflow.
If you're asking if it's possible, then yes, it's possible. Remote actors are basically interprocess communication. If you set everything up on both machines to a state where both can properly handle the future, then it should be good. You don't give any working example so I can't really delve deeper into it.

Asynchronous Initialization of Akka Actors

I'm trying to find the proper pattern for initializing an actor asynchronously, so that I can look up dependent ActorRefs it needs. I want to avoid using ActorSelection, since it's
ambiguous as to the number of actors it points to, and
has some overhead that's undesirable for many tells
Looking at the Actor LifeCycle it seems to be all pretty much synchronous until the message loop starts, including preStart, etc., which leads me to think that I have only one of two choices:
Use a factory method with a signature of Future[ActorRef]
All dependencies for constructing the actor are resolved asynchronously and passed in via Props.
The main problem with this approach is that you cannot use this factory to construct an actor inside of another actor, since it then has the same problem, i.e. it's turtles all the way down, wiring up the hierarchy of all actors and their dependencies asynchronously.
Use become and stash to transition the actor
The actor is created with actorOf, immediately resulting in an ActorRef but it starts in an Initialization state, does it's dependency resolution, stashing incoming messages in the meantime, and finally becomeing the Running state and unstashAlling.
This feels a lot more idiomatic for actors, even though my dependencies will all be var instead of val.
Both seem like a lot of overhead, making me wondering if I these are the best options or if I just haven't found the proper pattern in the docs.
There's no reason your dependencies have to be vars when using become:
val initializing: Actor.Receive = {
case Dependencies(d1, d2) => context.become(working(d1, d2))
}
def working(d1: Dependency, d2: Dependency): Actor.Receive = {
case msg => d1.fetch(...) // whatever
}
def receive = initializing
Also, actorFor is a) deprecated and b) doesn't create an actor.