The answers to your questions are as follows:
1) Yes, the actor will receive the message as long as you used the scheduler scheduleOnce
variant that takes an ActorRef
as an arg. Because an ActorRef
is just a lightweight proxy based on an actor address, it can survive failures of the target actor and still route messages to it as long as it successfully restarts back up and re-binds to the address that the ActorRef
represents/
2) Yes, if the ActorRef
is for a path that is no longer represented in the ActorSystem
then the message will be sent to deadletter instead.
3) Yes you will. If you do it in preStart
or in the body of the actor (constructor) and the actor fails and restarts, then the scheduled will now have two jobs to do for the same ActorRef
and thus two requests will eventually be received.
A little code to show all of this in action. Consider the following actor:
class TestSchedActor extends Actor{
import context._
override def preStart = {
context.system.scheduler.scheduleOnce(1 second, self, "bar")
}
def receive = {
case "foo" =>
val s:String = null
s.length
case "baz" =>
context stop self
case other =>
println(s"Got $other")
}
}
If you tested it in this way:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "foo"
Then the output would be:
[ERROR] [04/03/2014 07:58:24.988] [schedtest-akka.actor.default-dispatcher-2] [ akka://schedtest/user/$a] null
java.lang.NullPointerException
at code.TestSchedActor$$anonfun$receive$1.applyOrElse(Asking.scala:27)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
at akka.actor.ActorCell.invoke(ActorCell.scala:456)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
at akka.dispatch.Mailbox.run(Mailbox.scala:219)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
Got bar
Got bar
This shows both #1 and #3 as the actor still received the message after failure and actually received 2 as it re-scheduled again when it was restarted.
If you tested the actor like this:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
Then you would see the following output:
[INFO] [04/03/2014 08:01:14.199] [schedtest-akka.actor.default-dispatcher-2] [akka://schedtest/user/$a] Message [java.lang.String] from
Actor[akka://schedtest/user/$a#687201705] to Actor[akka://schedtest/user/$a#687201705] 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'.
Provided you had not disabled deadletter logging.