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.. :)
Related
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.
In my application, I'd like to broadcast a time unit every 2 sec to all actors instances of Worker. The time unit is sent by the master to all the workers.
I am trying to send a broadcast message to all workers by the master actor, but it doesn't work with me. I attach my test code here. There is a compile error in the line
router ! Broadcast("any message")
"Error: value is not a member of `akka.routing.Router`.
Could anyone tell me what is the problem here even I defined the router as an akka.routing.Router variable. Also, How can I broadcast this time_unit message every 2 sec?
Is it logically accepted to broadcast messages to local actors via routers?
Can I broadcast a message to every actor with different types that I defined in my application without specifying its type or even joined in a specific router.
import akka.actor._
import akka.routing.{ ActorRefRoutee, RoundRobinRoutingLogic, Router }
import akka.routing.Broadcast
import akka.routing.RouterActor
object Messages{
object Work
object Terminated
object Time_Unit
}
object MainRouterDriver extends App {
import Messages._
val system = ActorSystem("HelloSystem")
val routingMaster = system.actorOf(Props[Master], name = "helloactor")
routingMaster ! Work
}
class Worker extends Actor{
def receive = {
case _ =>
println("Hi I am a Worker")
}
}
class Master extends Actor {
import Messages._
var router = {
val routees = Vector.fill(5) {
val r = context.actorOf(Props[Worker])
context watch r
ActorRefRoutee(r)
}
akka.routing.Router(RoundRobinRoutingLogic(), routees)
}
def receive = {
case Work =>
router ! Broadcast(Time_Unit)
}
}
You can use
router.route(msg, sender())
It must work.! Take a look here
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.
So I'm getting started using Akka actors inside of my Play 2.0 app. I noticed quickly that repeated calls to sending messages to the same actor, specified via:
val myActor = Akka.system.actorOf(Props[MyActor], name = "myactor")
Resulted in InvalidActorNameException.
I then started reading up on the creation of Actors in this doc
The doc seemed to recommend creating a "master" Actor class with all of the individual actors specified in there. The receive of this actor class would, in turn, match on the message and delegate the message to the appropriate Actor.
So I tried this and now have something like:
class MasterActor extends Actor{
import context._
val emailActor = actorOf(Props[EmailActor], name = "emailActor")
protected def receive = {
case reminder : BirthdayReminder => emailActor ! reminder
}
}
Problem is that I'm in the same situation I was before. I don't know how to avoid the InvalidActorNameException when I try something like:
val myActor = Akka.system.actorOf(Props[MasterActor], name = "MasterActor")
myActor ! BirthdayReminder(someBirthday)
So what's the right way to organize my Actors?
If you want only one MasterActor, why are you creating multiple ones? You should just look up the one you have already created:
val actorRef = context.actorFor("MasterActor")
actorRef ! BirthdayReminder(someBirthday)
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.