I have a pretty simple actor defined as:
object CoreActor extends Actor with ActorLogging {
// val SYSTEM_NAME = "CoreActors"
val system = Akka.system()
// val system = ActorSystem.create("push", ConfigFactory.load.getConfig("push"))
val pushUri = Play.current.configuration.getString("pushservice.uri").getOrElse("akka.tcp://CentralappPush@127.0.0.1:5000")
val protocol = Play.current.configuration.getString("pushservice.protocol").getOrElse("akka.tcp")
val pushSystem = Play.current.configuration.getString("pushservice.system").getOrElse("CentralappPush")
val ip = Play.current.configuration.getString("pushservice.ip").getOrElse("127.0.0.1")
val port = Play.current.configuration.getInt("pushservice.port").getOrElse(5000)
val rootPath = Play.current.configuration.getString("pushservice.path.root").getOrElse("user")
val actorPath = Play.current.configuration.getString("pushservice.path.actor").getOrElse("PushMaster")
val selectionPath = RootActorPath(new Address(protocol, pushSystem, ip, port)) / rootPath / actorPath
val pushActor = context.actorSelection(selectionPath)
def receive = {
case pprs: List[PlaceProvider] => {
log.info("I received something")
pushActor ! pprs.map(_.clone)
context become afterSend
}
}
def afterSend: Receive = {
case pprs: List[PlaceProvider] => {
pprs.foreach(_.update) // update in the db
context.stop(self)
}
case _ => {
log.info("Did not understand message")
context.stop(self)
}
}
}
The actors are created with unique names from within a controller in the Play! framework. What I'm seeing is that when an actor is created for the first time of a place update, it does it's job and goes into the shutting down context as expected. A second call to the same action within the play framework causes this:
[ERROR] [02/18/2015 12:32:46.181] [application-akka.actor.default-dispatcher-2] [akka://application/user/OlD1vFKVLn1424259166159] null
java.lang.NullPointerException
at actors.CoreActor$$anonfun$receive$1.applyOrElse(CoreActor.scala:29)
at akka.actor.Actor$class.aroundReceive(Actor.scala:465)
at actors.CoreActor$.aroundReceive(CoreActor.scala:11)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
at akka.actor.ActorCell.invoke(ActorCell.scala:487)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:238)
at akka.dispatch.Mailbox.run(Mailbox.scala:220)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Which is quite baffling. Why does that happen? Why does it happen only during the second time an actor of the same type is started?
You actor is an object
- this enforces that there is a single instance of the actor. When an actor is stopped it will go through some processing to cleanup its resources. Since on your next request you try to re-create a new actor using the same instance the creation is failing.
Try changing it to a class
.
class CoreActor extends Actor with ActorLogging {
}