How can I send message to actor from different class? - scala

I have two classes with different ActorSystem with their corresponding actors. How can actor from class1 send message to actor in class2?

Why do you have 2 ActorSystems? Unless you have a really good reason, you should create all your actors in the same ActorSystem. Creating an ActorSystem is very expensive and communication as well as error handling are harder. Here's a simple example of communication between actors:
class Foo extends Actor {
val barActor = context.actorFor("/user/bar")
def receive = {
case 'Send => barActor ! "message from foo!"
}
}
class Bar extends Actor {
def receive = {
case x => println("Got " + x)
}
}
object Main {
def main(args: Array[String]) {
val system = ActorSystem("MySystem")
val foo = system.actorOf(Props[Foo], "foo")
val bar = system.actorOf(Props[Bar], "bar")
foo ! 'Send
}
}
With system.actorFor or context.actorFor, you can retrieve an ActorRef for a given path. The path for user created actors always starts with /user and includes all parent actors. So if you have a hierarchy of 3 actors the path could be /user/actorA/actorB/actorC.

See the docs on Actor Paths. The actor path includes the actor system.
So for example if your actor systems are named system1 and system2, and both of your actors are top level actors named actor1 and actor2, you can get ActorRefs for them like:
// inside actor1
val actor2 = system.actorFor("akka://system2/user/actor2")
actor2 ! "Foo"
and
// inside actor2
val actor1 = system.actorFor("akka://system1/user/actor1")
actor1 ! "bar"

I am not really sure what are you asking about.
If the actor class is MyClass and the message object is Message, you just do
val myInstance = new MyClass()
myInstance ! Message
And that's it. You can call that from within any other actor.

Related

Play! scala and Akka: how to test if an actor A sent a message to an actor B?

I want to test that an actor A send a message to an actor B after have received a message.
I'm using Play! 2.5 and I use the factories since I need to inject some of my classes and things like wSClient inside the actors.
The Actor A looks like:
object ActorA {
trait Factory {
def apply(ec: ExecutionContext, actorBRef: ActorRef): Actor
}
}
class ActorA #Inject()(implicit val ec: ExecutionContext,
#Named("actor-b") actorBRef: ActorRef)
extends Actor with ActorLogging with InjectedActorSupport {
override def receive: Receive = {
case i: Long =>
log info s"received $i"
actorBRef ! (i+1)
}
And the actor B is even more simple:
object ActorB {
trait Factory {
def apply(): Actor
}
}
class ActorB extends Actor with ActorLogging {
override def receive: Receive = {
case _ =>
log error "B received an unhandled message"
}
}
But my test doesn't pass, it is said that the expected message doesn't arrive, I get a Timeout in the test (but it is well logged by the actor B) so the problem comes from the test (and probably the Probe).
Here is the test:
val actorBProbe = TestProbe()
lazy val appBuilder = new GuiceApplicationBuilder().in(Mode.Test)
lazy val injector = appBuilder.injector()
lazy val factory = injector.instanceOf[ActorA.Factory]
lazy val ec = scala.concurrent.ExecutionContext.Implicits.global
lazy val factoryProps = Props(factory(ec, actorBProbe.ref))
val ActorARef = TestActorRef[ActorA](factoryProps)
"Actor B" must {
"received a message from actor A" in {
ActorARef ! 5L
actorBProbe.expectMsg(6L)
}
}
I also created a minimum Play! application with the code above available here.
In your test, actorBProbe is not the ActorB ref passed to ActorA constructor (of ref ActorARef). What really happens is that Guice creates a different ActorB (named actor-b), and passes its ref to ActorA (of ref ActorARef) constructor.
The test ends up with ActorB actor-b receiving 6L (as evident in log). While actorBProbe receives nothing.
The confusion really comes from mixing Guice lifecyle with Actors. In my experience, it creates more pains than I can bear.
To prove, simply print hash code of ActorRef's, you'll see they are different. Illustrated as followings:
val actorBProbe = TestProbe()
println("actorBProbe with ref hash: " + actorBProbe.ref.hashCode())
And,
class ActorA ... {
override def preStart =
log error "preStart actorBRef: " + actorBRef.hashCode()
// ...
}
In fact, even ec inside ActorA is not the same ec in the test code.
The following is a way to "force" the test to pass and at the same time prove that actorBProbe wasn't really being used by ActorB.
In stead of relying on Guice to "wire in" ActorB, we tell Guice to leave it alone by replacing #Named("actor-b") with #Assisted, like this,
import ...
import com.google.inject.assistedinject.Assisted
class ActorA #Inject()(...
/*#Named("actor-b")*/ #Assisted actorBRef: ActorRef)
...
Re-run the test, it'll pass. But this is probably not what you wanted to begin with.

In akka, what's correct pattern to use one (and only one) actor that's not a child?

I have 2 actors :
class ActorA extends Actor {
def receive = ???
}
object ActorA {
val actorA = system.actorOf(Props[ActorA])
}
class ActorB extends Actor {
def receive = {
case aMessage => ActorA.actorA ! aMessage
}
}
I want the actorA to have at any time only one instance (to apply a kind of back pressure)
But with the code above, if there's an error in the ActorA actor, the actor is restarted and the ActorRef actorA is no longer correct.
What's the correct pattern to use in this case ? Must I use ActorSelection ?
Yes. .actorOf() creates an actor
Assuming your two actors are created once in an init Class/Object/Main
val actorA = system.actorOf(Props[ActorA])
val actorB = system.actorOf(Props[ActorB])
Recover the reference to the existing ActorA from the context
class ActorB extends Actor {
val aA = context.actorSelection( "/user/ActorA" )
def receive = {
case aMessage => aA ! aMessage
}
}
Alternatives are
pass ActorA ActorPath or its reference to the constructor of ActorB
create ActorA as a child of ActorB (if that makes sense in your case)
Basically it seems you want a singleton in a distributed system.
Firstly I'd like to highlight that this can get you in trouble if you don't handle partitions very well. Secondly, if you're only on 1 node, than that's not a problem. And lastly, this is implemented as Akka's built-in cluster-singleton, so you can give it a look.

Testing preStart function of Akka actor

There is parent actor which in preStart creates child actors, one for every "active" user. Now I'd like to write a test asserting that it really happens, I mean child actors are really created for preconfigured users.
class IntegrationActor(settingsDao: UserSettingsDAO, childMaker: ActorRefFactory => UserId => ActorRef) extends Actor with StrictLogging {
val createUserActor = childMaker(context)
override def preStart(): Unit = {
val e = settingsDao.findAllEnabled()
e.map(_.userId).foreach(createUserActor)
}
// ...
}
I have test like this, but it doesn't work as all is happening off-main-test-thread
// mockMaker is already defined/mocked
it should "create child actors for users with enabled integration when started" in {
// given
val us = UserSettings(...)
Mockito.when(settingsDao.findAllEnabled()).thenReturn(Set(us))
// when
system.actorOf(Props(new IntegrationActor(settingsDao, mockMaker)))
// then
verifyMockMakerCalledFor(us)
}
I was trying to assign CallingThreadDispatcher to parent actor, but with no luck.
Theoretically I could just new this class and test it as usual, but Actor's can't be new-ed by hand.
Is there any other way to do this other than extracting stuff to trait with self type being Actor? Not sure it's the right way.

How to manage actor shutdown in a singleton ActorSystem

I have a singleton actor system in my application, and this works perfectly fine except that when the same application is loaded and unloaded inside the same JVM for testing, I have an error because I try, in my startup procedure, to recreate an actor which already exists.
As a result I get an akka.actor.InvalidActorNameException because the Actor name is not unique.
I am looking for a way to smoothly shutdown the actors depending on the actor systems without shutting down the actor system itself. Which is a reasonable strategy for that?
This is not exactly answer to your question - "... a way to smoothly shutdown the actors ...", but you mentioned that you are able to able to start two applicatons in same JVM.
Could you make your actor system to be singleton within application instance instead of singleton within whole JVM?
You would have two independent actor systems, you won't have name conflicts and won't have to start/stop specific actors.
I guess problems could be if some of actors are interacting with outside world, for example consuming some messages from JMS etc. Then it would not be obvious which actor system is processing them.
Do you want somethings like this ?
object AkkaTest extends App {
import akka.actor._
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
val system = ActorSystem.create
val supervisor = system.actorOf(Props[MasterOfPuppets], name = "masterOfPuppets")
private object AllTerminated
private class MasterOfPuppets extends Actor {
var supervised = 0
var waiterForTerminated: Option[ActorRef] = None
def receive = {
case actor: ActorRef =>
context.watch(actor)
supervised += 1
case Terminated(dead) =>
supervised -= 1
if (supervised == 0) {
waiterForTerminated.map(_ ! AllTerminated)
waiterForTerminated = None
}
case AllTerminated =>
if (supervised == 0) {
sender ! AllTerminated
} else {
waiterForTerminated = Some(sender)
}
}
}
private class TestedActor extends Actor {
def receive = {
case a: Any => sender ! a
}
}
implicit val timeout = Timeout(5.seconds) // needed for `?` below
// Create first actor
val actor1 = system.actorOf(Props[TestedActor], name = "name1")
supervisor ! actor1
actor1 ! PoisonPill
val waitForIt = supervisor ? AllTerminated
Await.result(waitForIt, 5.seconds)
// Same name
val actor2 = system.actorOf(Props[TestedActor], name = "name1")
supervisor ! actor2
println("ok then")
}
Your problem is very simple : Akka and message are asynchronous. If you try to create an actor just after you kill him, the name is not available.
Try just a Thread.sleep before creating new actor and it will work.. :)

Message passing using Actors

I am writing a program using Actors in scala in which an actor (Actor1) accepts two numbers as command line arguments and sends a message to another actor Actor2 (which calculates their sum). Actor2 sends the result to Actor1, who prints it on the screen.
class Actor1 extends Actor {
def main(args: Array[String]) {
val n= Integer.parseInt(args(0))
val k= Integer.parseInt(args(1))
val actor2 = new Actor2
actor2 ! (n, k)
}
def act()
{
react{
case num: Integer =>
println(num)
case _=>
println("Sum not received")
exit
}
}
}
class Actor2 extends Actor {
def act(){
loop
{
react
{
case(n:Int, k:Int) =>
val i = n + k
val actor1 = new Actor1
actor1 ! i}
}
}
}
Is it possible to define main() inside the class that extends Actor, and is there any other way to accept command line arguments by the Actor?
It shows the error: class Actor1 needs to be abstract, since method act in trait Reactor of type ()Unit is not defined.
First things first: You should consider using akka instead of the default Scala actors. It's just better.. in pretty much every aspect.
That aside, here are a few answers for your:
Your main method should be in a standalone object (not a companion object). So use something like this: object Main { def main(args:Array[String]) { ... } } and start your program via the Main object/class. (This is due to the definition inside the Actor1 class being non-static and the problem that if you define a companion object the .class filenames collide.)
In your code, something seems to have gone wrong with the brackets - or did you place Actor2 inside the Actor1 class on purpose? It's cleaner, if you just make three separate classes/objects: Actor1, Actor2, Main.
When you create Scala actors, you have to explicitly start them (not so with akka 2.x). So you miss your calls to actor1.start and such. Note that your program will then not terminate before your actors have terminated, so don't wonder if it doesn't stop anymore after you add that.
Finally, some minor hints:
You may want to consider using !? and send back your answer to the original caller, as this also allows you to have a proper termination condition.
Integer.parseInt("0") can be written more simply as "0".toInt