问题
In experimenting with Akka actors, I cooked up a use case which doesn't quite work as expected. I've defined an actor, MyActor
which receives a "start"
message. This message kicks off a scheduler which should relays a message "request"
to it self
every 1 second
. Here's the code:
import akka.actor._
import scala.concurrent.Await
import scala.concurrent.duration._
import akka.pattern.gracefulStop
import scala.concurrent.ExecutionContext.Implicits.global
object ScheduledActors {
def main(args: Array[String]) {
implicit val system = ActorSystem("ScheduledActors")
val admin = system.actorOf(Props[MyActor], name = "my-actor")
admin ! "start"
val adminFuture = gracefulStop(admin, 2 minutes)
Await.result(adminFuture, 2 minutes)
}
class MyActor extends Actor {
var cancellableOption: Option[Cancellable] = None
def receive = {
case "start" =>
println("start")
cancellableOption =
Some(context.system.scheduler.schedule(0 seconds, 1 second) { self ! "request" })
case "request" =>
println("request")
case "stop" =>
println("stop")
cancellableOption match {
case None => // no-op
case Some(v) => v.cancel()
}
context.stop(self)
}
}
}
I've experimented with a handful of variants. Leveraging the schedule
method variant with an explicit ActorRef
and message
. E.g.:
schedule(initialDelay: Duration, frequency: Duration, receiver: ActorRef, message: Any): Cancellable
In each case, the "request"
message appears to never have been received by the actor. The block is most certainly called as I've verified with println
statements as a sanity check. But delivery is a no-go.
This lead me to consider the self
reference might not provide the same context when actually executed in this context (à la ForkJoinPool invocation). The Akka documentation does warn against using unstable references in the context of a schedule invocation. However self
as a receiver is explicitly cited as a reasonable alternative.
I'm at a bit of a loss here at this point. Any help is greatly appreciated.
回答1:
It's because the actor is already terminated. When running, you should see dead letters logged, e.g.:
[INFO] [04/08/2014 17:05:03.903] [ScheduledActors-akka.actor.default-dispatcher-2] [akka://ScheduledActors/user/my-actor] Message [java.lang.String] from Actor[akka://ScheduledActors/user/my-actor#-1824493491] to Actor[akka://ScheduledActors/user/my-actor#-1824493491] 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'.
GracefulStop does not know about the scheduling you have done and stops the actor because the mailbox is empty. If you would change the main method to the following, you should see the messages:
implicit val system = ActorSystem("ScheduledActors")
val admin = system.actorOf(Props[MyActor], name = "my-actor")
admin ! "start"
Thread.sleep(5000)
admin ! "stop"
来源:https://stackoverflow.com/questions/22940199/akka-scala-actor-scheduled-message-does-not-appear-to-fire