问题
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?
回答1:
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.
回答2:
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.. :)
来源:https://stackoverflow.com/questions/14808752/how-to-manage-actor-shutdown-in-a-singleton-actorsystem