3
object Main extends App {

  //val name: String = "Apka"
  val system = ActorSystem()
  val worker = system.actorOf(Props[Worker], name = "workerActor")

  worker ! "test"
  worker ! FetchUrl(new URL("http://google.com"))

  println("test")

  //Await.time

  val stopped: Future[Boolean] = gracefulStop(worker, 15 seconds)
  Await.result(stopped, 16 seconds)
  system.shutdown()
}

我正在尝试使用 sbt 和 ~run 选项测试 scala 应用程序,但是使用这种方法,系统会在所有队列为空之前停止,没有它我必须重新启动整个 sbt。有没有办法在设定的时间段之后停止演员系统,或者在所有演员队列都为空之后?

4

1 回答 1

4

您应该阅读这篇文章,因为它描述了一种非常好的优雅关闭技术:

http://letitcrash.com/post/30165507578/shutdown-patterns-in-akka-2

但总而言之,您基本上设置了一个Reaper参与者,负责在所有创建的参与者实例都停止时关闭系统。创建的每个实例都会向 reaper 注册自身DeathWatch。然后,可以向每个参与者发送一个PoisonPill,以确保他们PoisonPill在停止之前已经处理了在第一个之前到达的所有消息。当他们都停下来时,收割者踢了进来并停止了ActorSystem。一个快速而肮脏的 impl 可能看起来像这样:

case class WatchMe(ref: ActorRef)
class ShutdownReaper extends Actor {
  val watched = ArrayBuffer.empty[ActorRef]

  def receive = {
    case WatchMe(ref) =>
      context.watch(ref)      
      watched += ref
    case Terminated(ref) =>
      watched -= ref      
      if (watched.isEmpty) context.system.shutdown
  }
}

case class FetchUrl(url:URL)
class Worker extends Actor{
  override def preStart = {
    context.system.actorSelection("/user/reaper") ! WatchMe(context.self)
  }

  def receive = {
    case FetchUrl(url) =>
      //Do something here, sleeping to fake work
      Thread.sleep(5000)
  }
}

object ReaperTest{
  def main(args: Array[String]) {
    val system = ActorSystem("test")

    val reaper = system.actorOf(Props[ShutdownReaper], "reaper")
    val worker1 = system.actorOf(Props[Worker])
    val worker2 = system.actorOf(Props[Worker])

    worker1 ! FetchUrl(new URL("http://www.google.com"))
    worker2 ! FetchUrl(new URL("http://www.cnn.com"))

    worker1 ! PoisonPill
    worker2 ! PoisonPill
  }
}

大部分代码在帖子中看起来很熟悉,但为了简洁起见,我对其进行了一些简化。

于 2013-08-12T23:34:34.997 回答