Scala 当后台参与者必须完成任务时,延迟关机

Scala 当后台参与者必须完成任务时,延迟关机,scala,akka,Scala,Akka,我有一个Akka应用程序,其中有一个路由器组,由执行某些作业的参与者组成。当我检测到应用程序关闭时,我希望我的参与者在完全关闭应用程序之前完成他们的工作。我的问题的用例是在重新部署的情况下:如果当前作业没有执行,我不想授权它 要检测应用程序的关闭,我使用以下代码: scala.sys.addShutdownHook { // let actors finished their work } 为了进行一些测试,我添加了一个无限循环,以查看关闭挂钩是否被阻止,但应用程序是否结束,因此这不是我期望

我有一个Akka应用程序,其中有一个路由器组,由执行某些作业的参与者组成。当我检测到应用程序关闭时,我希望我的参与者在完全关闭应用程序之前完成他们的工作。我的问题的用例是在重新部署的情况下:如果当前作业没有执行,我不想授权它

要检测应用程序的关闭,我使用以下代码:

scala.sys.addShutdownHook { 
// let actors finished their work
}
为了进行一些测试,我添加了一个无限循环,以查看关闭挂钩是否被阻止,但应用程序是否结束,因此这不是我期望的行为

为了让我的演员完成他们的工作,我将在下面的文章中实现这个想法:

所以现在我正在寻找一种方法来忽略关闭钩子,并在我的工作人员执行所有作业时关闭所有资源和应用程序

@Edmondo1984评论后更新 我的主应用程序:

val workers = this.createWorkerActors()
val masterOfWorkers = system.actorOf(Master.props(workers), name = "master")

    this.monitorActors(supervisor,workers,masterOfWorkers)
    this.addShutDownHook(system,masterOfWorkers,supervisor)

def monitorActors(supervisor : ActorRef,workers : List[ActorRef], master : ActorRef) : Unit = {
    val actorsToMonitor = master +: workers
    supervisor ! MonitorActors(actorsToMonitor)
  }

  def addShutDownHook
  (
    system : ActorSystem,
    masterOfWorkers : ActorRef, // actor wrapping a ClusterGroup router, brodcasting a PoisonPill to each worker
    supervisor : ActorRef
  ) : Unit = {
    scala.sys.addShutdownHook {
      implicit val timeout = Timeout(10.hours) // How to block here until actors are terminated ?
      system.log.info("Send a Init Shutdown to {}", masterOfWorkers.path.toStringWithoutAddress)
      masterOfWorkers ! InitShutDown
      system.log.info("Gracefully shutdown all actors of ActorSystem {}", system.name)
      Await.result((supervisor ? InitShutDown), Duration.Inf)
      system.log.info("Gracefully shutdown actor system")
      Await.result(system.terminate(), 1.minutes)
      system.log.info("Gracefully shutdown Akka management ...")
      Await.result(AkkaManagement(system).stop(), 1.minutes)
      System.exit(0)
    }
  }
监督演员

case class Supervisor()  extends Actor with ActorLogging {

  var numberOfActorsToWatch = 0L

  override def receive: Receive = {
    case MonitorActors(actorsToMonitor) =>
      log.info("Monitor {} actors, received by {}", actorsToMonitor.length, sender().path)
      this.numberOfActorsToWatch = actorsToMonitor.length
      actorsToMonitor foreach(context.watch(_))

    case Terminated(terminatedActor) if this.numberOfActorsToWatch > 0 =>
      log.info("Following actor {} is terminated. Remaining alives actors is {}", terminatedActor.path.toStringWithoutAddress, this.numberOfActorsToWatch)
      this.numberOfActorsToWatch -= 1

    case Terminated(lastTerminatedActor) if this.numberOfActorsToWatch == 0 =>
      log.info("Following actor {} is terminated. All actors has been terminated",lastTerminatedActor.path.toStringWithoutAddress, this.numberOfActorsToWatch)
      // what I can do here ?
      //context.stop(self)

  }
}
application.conf

akka {
actor {
coordinated-shutdown {
    default-phase-timeout = 20 s
    terminate-actor-system = off
    exit-jvm = off
    run-by-jvm-shutdown-hook = off
  }
}
}

我不知道如何阻止主线程,最终导致应用程序死机。

这很容易通过在层次结构前面放置一个主管角色来实现:

当您需要关机时,您会向主管发送一条消息,并缓存发件人a 主管通过DeadWatch see订阅儿童死亡 主管将设置一个计数器变量来设置孩子的数量,然后向所有孩子发送一条消息,告诉他们尽快关机。当孩子们完成时,他们将终止他们自己。主管将收到通知并减少计数器 当计数器达到0时,主管将向服务器发送一条消息,表示关机已终止并自行终止。 您的代码将变成这样:

class Supervisor  extends Actor with ActorLogging {

  var shutdownInitiator:ActorRef = _
  var numberOfActorsToWatch = 0L

  override def receive: Receive = {
    case InitShutdown =>
      this.numberOfActorsToWatch = context.children.length
      context.children.foreach(context.watch(_))
      context.children.foreach { s => s ! TerminateSomehow } 
      shutdownInitiator = sender
    case Terminated(terminatedActor) if this.numberOfActorsToWatch > 0 =>
      log.info("Following actor {} is terminated. Remaining alives actors is {}", terminatedActor.path.toStringWithoutAddress, this.numberOfActorsToWatch)
      this.numberOfActorsToWatch -= 1

    case Terminated(lastTerminatedActor) if this.numberOfActorsToWatch == 0 =>
      log.info("Following actor {} is terminated. All actors has been terminated",lastTerminatedActor.path.toStringWithoutAddress, this.numberOfActorsToWatch)
      // what I can do here ?
      shutdownInitiator ! Done
      context.stop(self)

  }
}
在关机挂钩上,您需要一个对主管的引用,并使用ask模式:

Await.result(supervisor ? InitShutdown, Duration.Inf)
actorSystem.terminate()

我用一些代码更新了我的帖子,但我仍然不知道如何阻止我所有演员的终止。在处理监视器时,你只需要抓取发件人的引用