如何使用actors和sbt在代码更改后重新加载scala应用程序

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。是否有一种方法可以在设定的时间段后或所有actor队列为空后停止actor系统?

1个回答

4

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

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

但是总结起来,您基本上需要设置一个Reaper actor,该actor负责在所有创建的actor实例停止时关闭系统。每个被创建的实例都会向收割者注册DeathWatch。然后,可以向每个actor发送PoisonPill,以确保它们在停止之前先处理到达的所有消息。当它们全部停止时,收割者开始停止ActorSystem。一个快速而简单的实现可能看起来像这样:

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
  }
}

大部分代码都与帖子中的相似,但为了简洁起见,我进行了一些简化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接