FastTracks / TheAkkaWay

Akka Chinese Book / What should be included in it?
Apache License 2.0
19 stars 3 forks source link

Kill 不起作用? #45

Open PipsqueakH opened 7 years ago

PipsqueakH commented 7 years ago

Akka的文档里有 You can kill an actor by sending a Kill message. This will cause the actor to throw a ActorKilledException, triggering a failure. The actor will suspend operation and its supervisor will be asked how to handle the failure, which may mean resuming the actor, restarting it or terminating it completely.

// kill the 'victim' actor
victim ! Kill

我想让一个actor给自己发一个Kill消息,然后让parent来restart他

import akka.actor._
case class Msg(n: Int)

object MyActor {
  def props: Props = Props[MyActor]
}

class MyActor extends Actor {
  override def preStart() = {
    println("actor start")
    self ! Msg(1)
  }
  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    println("preRestart")
    super.preRestart (reason, message)
  }
  def receive = {
    case Msg(i) =>
      if(i == 10)
        self ! Kill
      //       throw new Exception("kill exception")
      else {
        println(s"receive ${i}")
        self ! Msg(i + 1)
      }
  }
}

object Parent {
  def props: Props = Props[Parent]
}

class Parent extends Actor {
  import akka.actor.OneForOneStrategy
  import akka.actor.SupervisorStrategy._
  import scala.concurrent.duration._
  OneForOneStrategy(maxNrOfRetries = 60, withinTimeRange = 1 minute) {
    case _: ActorKilledException     =>
      println("killed")
      Restart
    case _: Exception                =>
      println("other")
      Restart
  }
  def receive = {
    case t => println("this is e,,,," + t)
  }

  val c = context.actorOf(MyActor.props, "c")
}

object Main extends App {
  val system: ActorSystem = ActorSystem("helloAkka")

  val a = system.actorOf(Parent.props, "a")

}

得到的结果是

actor start
receive 1
receive 2
receive 3
receive 4
receive 5
receive 6
receive 7
receive 8
receive 9
[ERROR] [05/25/2017 17:08:25.209] [helloAkka-akka.actor.default-dispatcher-6] [akka://helloAkka/user/a/c] Kill (akka.actor.ActorKilledException: Kill)

并没有restart, 如果不用Kill, 而是直接抛出异常确实可以restart的,这是什么原因呢?

zqhxuyuan commented 7 years ago

Kill会实际上抛出的是ActorKilledException, 而这个异常在supervisor strategy的Decider是Stop,而不是Restart。

  final val defaultDecider: Decider = {
    case _: ActorInitializationException ⇒ Stop
    case _: ActorKilledException         ⇒ Stop
    case _: DeathPactException           ⇒ Stop
    case _: Exception                    ⇒ Restart
  }

如果要模拟Restart,可以在parent中将ActorKilledException的Decider改为Restart

gabrywu commented 6 years ago

@PipsqueakH 楼上是正解。不过你的需求还挺特殊的,使用actor一般会主动stop,很少见主动restart的。