The akka documentation is clearly stated that it is dangerous to create an actor within an actor like this:
class ActorA extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA))
}}
I understand that the Actor's apply method is accepting this reference of the creating actor. yet I couldn't understand (nor couldn't find any example) why this is harmful and what issues it can cause?
Let's tweak your example a little bit
class ActorA(str:String) extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA("hidden")))
}}
Most of the common use case of using actors are to handle failover and supervision, shen an actor fails and needs to be restarted, the actor system needs to know how to do that. When you use Props(Props(new ActorA)), you've hidden the parameter value of "hidden" by handling it yourself.
Rather than doing that if instead, you declare how to create instances of the actor, the actor system will know exactly what it needs to do when recreating an actor -
i.e. create an instance of ActorA with a constructor argument of "hidden".
Even with your example of Actor without param
context.actorOf(Props(new ActorA))
this way of instantiating actors within another actor is not recommended because it encourages to close over the enclosing scope, resulting in non-serializable Props and possibly race conditions (breaking the actor encapsulation).
I believe we are confusing creation and declaration. The doc says that
Declaring one actor within another is very dangerous and breaks actor encapsulation. Never pass an actor’s this reference into Props!
So the problem is declaration, not creation!
Let's look at Java's:
public class MyActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK", getSelf());
}
class MyOtherActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK-Inner", getSelf());
}
}
}
Now, if MyOtherActor was a normal class, we'd be able to instantiate it only from an instance of MyActor:
MyActor actor = new MyActor();
MyActor.MyOtherActor otherActor = actor.new MyOtherActor();
Which means that the constructor for MyOtherActor depends on the instance of MyActor!
Now, if Props are supposed to contain the "factory" of the actor. They need a factory method. If our MyOtherActor is declared as we did here, then our props would look like this (ish):
MyActor actor = ??? // how did you even get a reference to the actor and not the actorRef in the first place!
Props otherActorProps = Props.create(MyActor.MyOtherActor.class, () -> actor.new MyOtherActor());
And bang, here comes the kicker! Now your otherActorProps contains a reference to actor, i.e. you have closed over mutable state! If for whatever reason actor "dies", your props will still be referencing it, causing all sort of weirdness.
There is also the issue of how you get a reference to the actor in the first place, and not it's actorRef
IMHO, that's what the documentation is referring to, and not the fact of "creating" (i.e. instantiating, spawning) an actor within another one: that's absolutely normal and it's a routine operation of akka (that's why you can do getContext().actorOf(..) as well as actorSystem.actorOf(...)
The warning is there in the documentation because it's easy to accidentally close over the creating actor's state, including its this pointer (which you should never use in actor-based code).
In my experience, I've usually seen a props method put into an actor's companion object:
object ActorA {
def props() = Props(new ActorA)
}
Doing it that way ensures the returned Props isn't closing over an actor's state.
class ActorB extends Actor {
def receive = {
case _ =>
val actorB = context.actorOf(ActorA.props)
...
}
}
It's not as big of a possibility for actors that don't take constructor parameters, but once parameters come into play you need to be careful about closing over internal state.
Related
Title is self-explanatory, I want to be able to send a message to a parent actor (meaning I want parent's ActorRef). In Akka Classic (untyped), the ActorRef for a parent actor can be obtained from the child's ActorContext via:
context.parent
(see, for instance, this question (in Java)).
However, the akka.actor.typed.scaladsl.ActorContext in Akka Typed does not expose an ActorRef for the parent. Is there an idiomatic means in Scala to obtain an ActorRef for the parent actor?
TLDR:
Inject the parent actor reference into the child when creating it.
Akka Typed enforces strict protocols, so you need to make it absolutely clear that "this actor talks to another actor". The accepted answer is a workaround (casting to classic and using the parent), but has its downsides: now you do not enforce types anymore.
Here is some code that should get you started. See how all the types are enforced. You can model the traits differently, but you should get the drift:
object ParentActor {
sealed trait Command
case class DoSomething() extends Command
// you do not have to do this, but creating another trait
// allows you to narrow the amount of messages the parent can receive from the child
sealed trait ChildNotification extends Command
case class MessageFromChild() extends ChildNotification
def apply(): Behavior[Command] = {
Behaviors.receive( (context, message) =>
message match {
case DoSomething() =>
// create a child that knows about its parent
context.spawn(ChildActor(context.self), "child")
Behaviors.same
case MessageFromChild() =>
context.log.info("I received a message from my child")
Behaviors.same
})
}
}
object ChildActor {
sealed trait Command
case class Work() extends Command
// inject the parent here (or any other actor that matches the signature)
def apply(parent: ActorRef[ParentActor.ChildNotification]): Behavior[Command] = {
Behaviors.receive( (context, message) =>
message match {
case Work() =>
// send message to parent actor (or any other actor with that type)
parent ! ParentActor.MessageFromChild()
Behaviors.same
})
}
}
By the way, I am using the "functional" syntax of akka typed, but you can use the more "object-oriented" syntax as well. It follows the same approach.
If you're in typed Akka, the only [Scala] type that could encompass ActorRefs of all possible parent actors is ActorRef[Nothing], which is an ActorRef you can't send messages to, so that's of limited utility.
At least for as long as the classic APIs exist:
import akka.actor.typed.scaladsl.adapter._
type ClassicActorRef = akka.actor.ActorRef
val parentActorRef = context.toClassic.parent
This will be an untyped ActorRef, i.e. you're free to send messages which the parent actor will never accept.
If you want a typed reference to an actor's parent, you'll need to embed that when spawning the child actor, just as if you want a typed reference to the sender of the current message you need to embed replyTos in your protocol.
(context.sender is absent in the typed ActorContext for the same reason that context.parent is absent; the workaround for replicating classic context.sender is analogous: context.toClassic.sender)
In my Scala application say I have Actor A and Actor B. I want to devise a test case in ScalaTest that would allow me to send a message to Actor A and see what message it sends to Actor B in order to see if A is properly processing it's data and sending the right message to B. How would one test this? It took me a long time to get this cooked up on my own...but it does seem to mostly work.
class A extends Actor { ... }
class B extends Actor { ... }
class C(p: TestProbe) extends B {
override def receive = {
LoggingReceive {
case x =>
println(x.toString)
p.ref ! x
}
}
}
case class MsgToB(...)
// Spec class which extends TestKit
"A" should {
"send the right message to B" {
val p = TestProbe()
val a = TestActorRef[A]
val c = TestActorRef(Props(new C(p)))
// Assume A has a reference to C. Not shown here.
a ! msg
// Assert messages
p.expectMsgType[MsgToB]
}
}
Is this the best means of doing this? Is there a better practice?
To me it sounds like what you want is to test the behaviour of actor A in isolation. In order to do this, you need to be able to control how actor A gets its reference to actor B. For example, you could provide the reference in the actor's constructor:
import akka.actor.{Actor, ActorRef, Props}
class A(refToB: ActorRef) extends Actor { ... }
object A {
def props(refToB: ActorRef): Props = Props(new A(refToB))
}
There are alternative ways you can pass the reference to actor B to actor A, but using the constructor is arguably the easiest choice. In the example above, we also provide a method for creating the correct Props for the actor.
Now that you can control the reference to actor B, you can replace the actor reference with test probe in tests.
import akka.testkit.TestProbe
// Initialise a test probe
val probe = TestProbe()
// Actor A with reference to actor B replaced with the test probe
val a = system.actorOf(A.props(probe.ref))
// Send a message to actor A
a ! someMessage
// Verify that the probe received a correct response from actor A
p.expectMsgType[MsgToB]
Notice that I created the actor using the actor system from the TestKit instead of using the TestActorRef. This means that the actor message processing will be asynchronous instead of synchronous. Personally, I've found the asynchronous testing style to be a better fit because it better represents how the actor is run in a production system. Asynchronous testing is also recommended in the official documentation.
I use IntelliJ IDEA, but the question could relate to other IDEs. There is a great way to navigate the code with Ctrl+click. From the method call it jumps to the method declaration. It really boosts the productivity.
Actor systems are based on message passing. Example in Akka with Scala:
class MyMessage
object MyMessage
class MyActor1 extends Actor {
context.actorOf(Props[MyActor2]) ! MyMessage
}
class MyActor2 extends Actor {
def receive = {
case MyMessage =>
...
}
}
Is there a way to navigate in code between sending the message and receiving the message?
I mean clicking on ! will take me to the definition of ! method in ScalaActorRef, but that's 99% chance that I don't want that. Jumping to the corresponding receive method (or, if possible, to correct case: case MyMessage) would be more appropriate.
How do you navigate the code between actors?
I don't think it is possible in general because an actor can change its behavior at runtime, including what messages it can process - as opposed to methods which can be statically indexed. For example, receive function may be computed depending on the actor state:
class MyActor extends Actor {
var i = 0
def receive = firstReceive
def commonReceive = {
case Increment =>
i += 1
if (i % 3 == 0) context.become(firstReceive)
else context.become(secondReceive)
}
def firstReceive = commonReceive orElse {
case Ping =>
sender ! "zero"
}
def secondReceive = commonReceive orElse {
case Ping =>
sender ! "one or two"
}
}
Now the actor handles messages differently depending on which messages it handled before. And this is only a simple example - actual actor behavior may even be received from the outside!
case class Behavior(receive: Actor.Receive)
class MyActor extends Actor {
def receive = {
case Behavior(r) => context.become(r)
}
}
Another difficulty which is even greater is that you usually have an ActorRef to which you send messages with !. This ActorRef has no static connection with the actor class which contains message handling logic - it is instantiated with Props which can use arbitrary code to determine which actor class should be used:
val r = new Random
val a = actorSystem.actorOf(Props(if (r.nextInt(100) > 50) new FirstActor else new SecondActor))
a ! Message // which handler should this declaration lead to?
This makes finding actual message handler next to impossible.
If you think that it may be worth it to support simpler cases, like the one you provided, you can always submit a feature request to YouTrack.
Not perfect, but what could help would be to use Find Usage (Alt+F7) on the type of the message. For that you probably have to navigate to the type Declaration (Ctrl+Shift+B) first
I wonder if there is an easy way to create a shortcut for the combination.
Another idea would be to use the Structural Search which might be able to find things like excpressions, that match on the class name ...
Once you created a template to your liking you can then record a macro
is it possible in Akka (scala) to get a reference to an existing ActorSystem?
I am working on a Spray application with another Actor for DB. I am also extending Directives to have an object per path. the directives are not actors by themselves, but they need to pass messages to the DBActor. here:
class HttpActor extends Actor with HttpService {
val actorRefFactory = context
def receive = runRoute(
IndexService.route ~
HostsService.route
)
}
object HostsService extends Directives{
def route(implicit dm: DetachMagnet2) = {
path("hosts") {
get {
detach() {
**dbActor ! CreateHost**
complete("get me hosts!")
}
} ~
post {
detach() {
entity(as[String]) { payload =>
complete(s"post hosts $payload")
}
}
}
}
}
}
is there a way for HostsService to discover the ActorSystem itself so he can find the DBActor, or must HttpActor pass it in? the latter seems less elegant, as it HostsService will need to become a class (not an object), so no longer a singleton.
From here:
there was a ticket for creating such a registry, but we were not
satisfied with what we got when trying to specify the semantics in
detail. One part is that we removed all global state so that different
parts of an application can use Akka without having to worry about
each other and a global feature would break this. Another is that it
would encourage get-or-create usage—my pet peeve—which would make the
semantics unclear: you give a name and a config, but if the name
already exists you potentially get back a differently configured
system (which is usually quite fatal).
There is nothing stopping you from putting a hashmap in some central
place of your application, (pre-)populate that with the actor systems
you need and be done, that's basically a one-liner (which is another
reason for not including it in Akka, because instead of a simple
solution to a very narrow problem we'd have to think of a solution to
a much more generic problem)
In your case, it's better to pass your system implicitly to the route function:
class HttpActor extends Actor with HttpService {
implicit val actorRefFactory = context
def receive = runRoute(
IndexService.route ~
HostsService.route
)
}
object HostsService extends Directives {
def route(implicit dm: DetachMagnet2, as: ActorContext) = {...}
}
I noticed it is legal to write this scala code:
val fussyActor = actor {
loop {
receive {
case s: String => println("I got a String: " + s)
case _ => println("I have no idea what I just got.")
}
}
}
I know from documentation that actor is a trait, which has loop and receive value members. But how is it possible to stack these methods like above? Is it implementing or overriding these methods? I am quite confused at this syntax. Please provide some good references/pointers.
First, a standard disclaimer. Scala Actors have been deprecated in favor of Akka Actors. If you want to continue down the path of learning to use Actors with Scala, you should look into Akka instead of researching Scala Actors.
Now, about your question. There are a couple of things in play here, so let's first start out with what you need to do in order to define a new Scala Actor. If you look at the Scala Actor trait, you see that there is one abstract method that you must provide called act():Unit. This is a method that takes no inputs and returns no inputs. It defines the actors behavior. So in it's simplest form, a custom Scala Actor could be:
class MyActor extends Actor{
def act(){
}
}
Now this not a very interesting actor as it does nothing. Now, one way to provide behavior is to invoke the receive method, providing a PartialFunction[Any,R] where R is a generic return type. You could do that like so:
class MyActor extends Actor{
def act(){
receive{
case "foo" => println("bar")
}
}
}
So now if this actor receives a message "foo", it will print "bar". The problem here is that this will only happen for the first message and then won't do anything after. To fix that. we can wrap our call to receive with a call to loop to make it continue to do the provided receive call for each received message:
class MyActor extends Actor{
def act(){
loop{
receive{
case "foo" => println("bar")
}
}
}
}
So this is now starting to look like your example a bit more. We are leveraging the loop and receive methods that come with the Actor trait in order to give this actor behavior. Lastly, instead of defining an explicit class as my actor, I can define one on the fly with the actor method on the Actor companion object. That method takes a function body that will be used as the act impl like this:
def actor(body: => Unit){
val a = new Actor {
def act() = body
override final val scheduler: IScheduler = parentScheduler
}
}
So in your example, you are creating a new actor implementation on the fly and providing an impl for act that will loop and call receive continually with the partial function you supplied for message handling.
Hopefully this clarifies things a bit. The only method you are "overriding" (providing an impl for) is act. When you see loop and receive, those are not overrides; they are simply calls to those existing methods on the Actor trait.
Actually it's illegal without import Actor._.
Your code without that import:
val fussyActor = Actor.actor {
Actor.loop {
Actor.receive { ... }
}
}
actor, loop and receive are methods of object Actor.
def actor(body: ⇒ Unit): Actor
def loop(body: ⇒ Unit): Unit
def receive[A](f: PartialFunction[Any, A]): A
Method actor accepts by-name Untit parameter body - some code block to execute in separate thread and creates an Actor with act method implemented using parameter body.
Method loop accepts by-name Untit parameter body - some code block to execute in infinite loop.
Method receive accepts PartialFunction as parameter f and calls f with message as parameter. It takes message from actor associated with current thread.
Note that scala actors are deprecated, you should use akka actors. See The Scala Actors Migration Guide.