Как перезапустить убитого актера? - PullRequest
0 голосов
/ 19 апреля 2019

У меня есть руководитель и дочерний актер, который выглядит следующим образом:

SupervisorActor.scala

import akka.actor.{Actor, ActorLogging, Props, Terminated}

object SupervisorActor {

  def props: Props = Props(new SupervisorActor)

  object KillFoo
  object TerminateFoo
  object RestartFoo

}

final class SupervisorActor extends Actor with ActorLogging {

  import com.sweetsoft.SupervisorActor._

  log.info(s"Start the actor ${self}")

  private val foo = context.actorOf(FooActor.props, "FOOCHILD")

  context.watch(foo)

  override def receive: Receive = {
    case KillFoo =>
      context.stop(foo)
    case Terminated(actor) =>
      log.info(s"Kill actor $actor")
    case TerminateFoo =>
      log.info("Terminate FooActor")
      foo ! new IllegalArgumentException
    case RestartFoo =>
  }
}

FooActor.scala

import akka.actor.SupervisorStrategy.{Escalate, Restart, Resume, Stop}
import akka.actor.{Actor, ActorLogging, OneForOneStrategy, Props}
import scala.concurrent.duration._

object FooActor {
  def props: Props = Props(new FooActor)
}

final class FooActor extends Actor with ActorLogging {

  log.info(s"Start the actor ${ self }")

  override val supervisorStrategy: OneForOneStrategy =
    OneForOneStrategy(maxNrOfRetries = 1, withinTimeRange = 1.minute) {
      case _: ArithmeticException => Resume
      case _: NullPointerException => Restart
      case _: IllegalArgumentException =>
        println("STOP exception raised.")
        Stop
      case _: Exception => Escalate
    }

  override def receive: Receive = {
    case _ => log.info("I got killed.")
  }
}

и Main.scala

import akka.actor.ActorSystem
import com.sweetsoft.SupervisorActor.{TerminateFoo}

import scala.concurrent.Future
import scala.io.StdIn

object Main extends App {

  val system = ActorSystem("monarch")
  implicit val dispatcher = system.dispatcher

  try {
    // Create top level supervisor
    val supervisor = system.actorOf(SupervisorActor.props, "mupervisor")
    // Exit the system after ENTER is pressed
    Future {
     Thread.sleep(2000)
      supervisor ! TerminateFoo
    }

    StdIn.readLine()
  } finally {
    system.terminate()
  }

} 

После того, как FooActor был убит, я хотел бы снова запустить его вручную, как я сделал:

private val foo = context.actorOf(FooActor.props, "FOOCHILD") 

Как это сделать?

Я думаю о создании функции, которая собирается создать FooActor, и после того, как она будет убита, просто вызовите функцию, чтобы запустить новую FooActor.

1 Ответ

4 голосов
/ 19 апреля 2019

Есть несколько проблем с кодом. supervisorStrategy должно быть в SupervisorActor, поскольку оно отвечает за присмотр, а не сам ребенок-актер.

foo ! new IllegalArgumentException не приведет к завершению дочернего актера, поскольку актеры могут принимать любой объект в качестве сообщения, а объекты, производные от исключения, не обрабатываются специально. Он просто напечатает «Я был убит». но в противном случае игнорируйте сообщение и продолжайте работать. В частности, он не будет вызывать supervisorStrategy обработчик.

Вы можете либо:

  • отправить предопределенное системное PoisonPill сообщение дочернему субъекту изящно остановить его (т.е. после обработки всех ожидающих сообщений)

  • отправить предопределенное системное Kill сообщение дочернему субъекту, чтобы остановить сразу после обработки текущего сообщения и игнорирования другие сообщения в очереди, если таковые имеются.

  • переслать TerminateFoo сообщение на него и бросить исключение в его обработчик. В этом случае ребенок судьба объекта определяется обработчиком supervisorStrategy для Тип исключения IllegalArgumentException (т.е. остановка в вашем случае).

.

override def receive: Receive = {
    case TerminateFoo =>
      log.info("Stopping FooActor by throwing an unhandled exception for supervisorStrategy to process it")
      throw new IllegalArgumentException
    case m => log.info(s"I received a message $m")
  }

Подробнее см. https://doc.akka.io/docs/akka/current/actors.html#stopping-actors

...