您应该阅读这篇文章,因为它描述了一种非常好的优雅关闭技术:
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
}
}
大部分代码在帖子中看起来很熟悉,但为了简洁起见,我对其进行了一些简化。