Search code examples
akkaactor

Akka: context become throws NullPointerException?


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?


Solution

  • 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 {
    }