1
votes

The default behavior of actor is restart. In order to get better understanding, I created two actors and a crash to cause the restart:

class PingActor extends Actor with ActorLogging {
  import PingActor._
  override def postRestart(reason: Throwable): Unit = {
    log.info(s"RESTARTING")
    super.postRestart(reason)
  }
  var counter = 0
  val pongActor = context.actorOf(PongActor.props, "pongActor")
  def receive = {
    case Initialize => 
      pongActor ! PingMessage("ping")   
    case PongActor.PongMessage(text) =>
      log.info("In PingActor - received message: {}", text)
      counter += 1
      if (counter == 3) {
         log.info("FIN")
        context.system.shutdown()
      }
      if (counter == 2) {
        sender() ! PingMessage("ping")
        throw new IllegalArgumentException("Aooch")

      }
      else sender() ! PingMessage("ping")
  } 
}
object PingActor {
  val props = Props[PingActor]
  case object Initialize
  case class PingMessage(text: String)
}

class PongActor extends Actor with ActorLogging {
  import PongActor._
  def receive = {
    case PingActor.PingMessage(text) => 
      log.info("In PongActor - received message: {}", text)
      sender() ! PongMessage("pong")
  }
}

object PongActor {
  val props = Props[PongActor]
  case class PongMessage(text: String)
}

so the PingActor is sending the message before the crash and PongActor replies when the Ping actor restarts it accepts the message but the sender (PongActor) is not available. I do see this line in deadLetters

[INFO] [MyActorSystem-akka.actor.default-dispatcher-4] [akka://MyActorSystem/user/pingActor/pongActor] Message [com.example.PingActor$PingMessage] from Actor[akka://MyActorSystem/user/pingActor#-1362690296] to Actor[akka://MyActorSystem/user/pingActor/pongActor#1725419686] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

why the sender that sent the message prior to the crash is not available ? is there a way to overcome it ?

1

1 Answers

0
votes

As the documentation states, the default behavior when an actor is restarted is to stop all of that actor's children. This is the reason that the message to sender after the restart goes to dead letters. You need to override the default behavior and set the initialization of the child (i.e., PongActor) in the preStart() hook. Also, remove the call to super.postRestart(reason).

class PingActor extends Actor with ActorLogging {
  import PingActor._

  override def preStart(): Unit = {
    pongActor = Option(context.actorOf(PongActor.props, "pongActor"))
  }

  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    log.info("Don't stop the children")
    postStop()
  }

  override def postRestart(reason: Throwable): Unit = {
    log.info("RESTARTING")
  }

  var counter = 0
  var pongActor: Option[ActorRef] = None

  def receive = {
    case Initialize => 
      pongActor.foreach(_ ! PingMessage("ping"))
    case PongActor.PongMessage(text) =>
      ...
  } 
}

Making the above changes results in the following output:

In PongActor - received message: ping
In PingActor - received message: pong
In PongActor - received message: ping
In PingActor - received message: pong
In PongActor - received message: ping
Don't stop the children
RESTARTING
In PingActor - received message: pong
In PongActor - received message: ping
In PingActor - received message: pong
In PongActor - received message: ping
Don't stop the children
RESTARTING
In PingActor - received message: pong
In PongActor - received message: ping
In PingActor - received message: pong
In PongActor - received message: ping
Don't stop the children
RESTARTING
In PingActor - received message: pong
In PongActor - received message: ping
...

More information on restarting in addition to the first link is found here.