Akka Scala actor scheduled message does not appear to fire

核能气质少年 提交于 2020-01-15 08:26:03

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!