Scala 当后台参与者必须完成任务时,延迟关机
我有一个Akka应用程序,其中有一个路由器组,由执行某些作业的参与者组成。当我检测到应用程序关闭时,我希望我的参与者在完全关闭应用程序之前完成他们的工作。我的问题的用例是在重新部署的情况下:如果当前作业没有执行,我不想授权它 要检测应用程序的关闭,我使用以下代码:Scala 当后台参与者必须完成任务时,延迟关机,scala,akka,Scala,Akka,我有一个Akka应用程序,其中有一个路由器组,由执行某些作业的参与者组成。当我检测到应用程序关闭时,我希望我的参与者在完全关闭应用程序之前完成他们的工作。我的问题的用例是在重新部署的情况下:如果当前作业没有执行,我不想授权它 要检测应用程序的关闭,我使用以下代码: scala.sys.addShutdownHook { // let actors finished their work } 为了进行一些测试,我添加了一个无限循环,以查看关闭挂钩是否被阻止,但应用程序是否结束,因此这不是我期望
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()
我用一些代码更新了我的帖子,但我仍然不知道如何阻止我所有演员的终止。在处理监视器时,你只需要抓取发件人的引用