Actor - Stopping actors

stop

Actors are stopped by invoking the stop method of a ActorRefFactory, i.e. ActorContext or ActorSystem. Typically the context is used for stopping the actor itself or child actors and the system for stopping top level actors. The actual termination of the actor is performed asynchronously, i.e. stop may return before the actor is stopped.

  1. system.stop 是停止顶级的actor
  2. context.stop 是在actor 内停止自己或者自己的子actor
  3. stop是异步的,执行stop那句的时候,实际上actor可能还没有真正的停止
  4. 当actor接受到stop消息时,如果当前正在执行某条消息,会继续这条执行,但这条后面的会被发到deadletter里
  5. 停止的过程是,先挂起自己的邮箱, 当此actor有子actor的时候给他们发stop消息,等他们的Terminated消息都返回的时候才给自己的监管者发送Terminated

PoisonPill

You can also send an actor the akka.actor.PoisonPill message, which will stop the actor when the message is processed. PoisonPill is enqueued as ordinary messages and will be handled after messages that were already queued in the mailbox.

  1. PoisonPill和一个普通消息是一样的,要排队,当执行到他的时候才去开始停止的过程

Graceful Stop

停止的过程中,可能出现的情况是. 停止是需要时间的,而且当子actor停止的时候出现意外情况,没有正常返回Terminated,整个停止过程不会终端会挂起.所以需要进行一些错误处理

import akka.pattern.gracefulStop
import scala.concurrent.Await

try {
val stopped: Future[Boolean] = gracefulStop(actorRef, 5 seconds, Manager.Shutdown)
Await.result(stopped, 6 seconds)
// the actor has been stopped
} catch {
// the actor wasn't stopped within 5 seconds
case e: akka.pattern.AskTimeoutException =>
}
object Manager {
case object Shutdown
}

class Manager extends Actor {
import Manager._
val worker = context.watch(context.actorOf(Props[Cruncher], "worker"))

def receive = {
case "job" => worker ! "crunch"
case Shutdown =>
worker ! PoisonPill
context become shuttingDown
}

def shuttingDown: Receive = {
case "job" => sender() ! "service unavailable, shutting down"
case Terminated(`worker`) =>
context stop self
}
}

gracefulStop 是一个封装好的停止actor的方法,参数可以提供timeout,相应的触发停止的消息,内部会帮你去接受Terminated并且unWatch相应的actor