Akka决策者是否有权访问全部故障场景?

Akka决策者是否有权访问全部故障场景?,akka,akka-supervision,Akka,Akka Supervision,阿卡新来的。创建扩展了SupervisorStrategy的新Scala类为我提供了以下模板: class MySupervisorStrategy extends SupervisorStrategy { override def decider: Decider = ??? override def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRe

阿卡新来的。创建扩展了
SupervisorStrategy
的新Scala类为我提供了以下模板:

class MySupervisorStrategy extends SupervisorStrategy {
  override def decider: Decider = ???

  override def handleChildTerminated(context: ActorContext, child: ActorRef,
    children: Iterable[ActorRef]): Unit = ???

  override def processFailure(context: ActorContext, restart: Boolean,
    child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = ???
}
我正在寻找一种访问的方式:

  • 从子参与者抛出的
    可丢弃的
    /
    异常
  • 引发异常的子actor
    ActorRef
  • 传递给子参与者并提示引发异常的消息
  • 我认为每当孩子抛出异常时,
    决策器(实际上是一个
    部分函数[Throwable,Directive]
    )就会通过
    Throwable
    ,但我不知道在哪里可以访问上面列表中的#2和#3有什么想法吗?


    更新 从张贴的小提琴来看,它看起来像一个有效的决策者是:

    {
        case ActorException(ref,t,"stop")      =>
          println(s"Received 'stop' from ${ref}")
          Stop
        case ActorException(ref,t,"restart")      =>
          println(s"Received 'restart' from ${ref}")
          Restart
        case ActorException(ref,t,"resume")      =>
          println(s"Received 'resume' from ${ref}")
          Resume
    }
    
    在上面,我看到了所有三个:

  • 由子级引发的异常
  • 引发异常的子项(
    ref
  • 最初发送给子级的消息(导致引发异常)
  • 看起来在
    决策者
    中没有任何需要在
    主管
    类中定义的内容。我想把
    Decider
    逻辑拉出来,比如说,
    MyDecider.scala
    并找到一种方法来重构
    Supervisor
    ,使其
    supervisorStrategy
    使用
    MyDecider
    的实例,因此可能类似于:

    class Supervisor extends Actor {
      import akka.actor.OneForOneStrategy
      import akka.actor.SupervisorStrategy._
      import scala.concurrent.duration._
    
      var child: ActorRef = _
    
      override val supervisorStrategy =
        OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute, decider = myDecider)
    
      ...
    }
    
    对于#2,您可以访问发送方“如果策略在监督参与者内部声明”

    如果策略是在监督参与者内部声明的(而不是在同伴对象内部),则其决策者可以以线程安全的方式访问参与者的所有内部状态,包括获取对当前失败子级的引用(可用作失败消息的发送者)

    该消息不可用,因此唯一的选项是捕获异常,并使用收到的消息抛出自定义异常

    这是一个

    类ActorSO扩展了Actor{
    def_接收:接收={
    案例e=>
    println(e)
    抛出新的RuntimeException(例如toString)
    }
    最终def接收={
    case any=>try{
    _接收(任何)
    }
    抓住{
    案例t:Throwable=>抛出新ActorException(self、t、any)
    }
    }
    }
    
    更新
    Decider
    只是一个
    PartialFunction
    ,因此您可以将其传递到构造函数中

    对象管理器{
    定义道具(决策者:决策者)=道具(新主管(决策者))
    }
    类监管者(decider:decider)扩展了Actor{
    覆盖val supervisorStrategy=OneForOneStrategy()(决策者)
    覆盖def接收:接收=???
    }
    类MyDecider扩展了Decider{
    覆盖def isDefinedAt(x:Throwable):布尔值=真
    覆盖def应用(v1:可丢弃):监管策略指令={
    案例t:ActorException=>Restart
    案例不匹配=>SupervisorStrategy.defaultDecider.apply(不匹配)
    }
    }
    对象测试{
    val myDecider:Decider={
    案例t:ActorException=>Restart
    案例不匹配=>SupervisorStrategy.defaultDecider.apply(不匹配)
    }
    val myDecider2=新的MyDecider()
    val系统=ActorSystem(“堆栈溢出”)
    val supervisor=system.actorOf(SupervisorActor.props(myDecider))
    val-supervisor2=system.actorOf(SupervisorActor.props(myDecider2))
    }
    
    这样做,您将无法访问通过
    sender()
    引发异常的子级的
    ActorRef
    这样的监控状态(尽管我们在
    ActorException
    中包含了这一点)

    关于您最初从主管处访问导致异常的子消息的问题,您可以看到(从akka 2.5.3)akka开发人员选择不将其用于决策

    final protected def handleFailure(f:失败):单元={
    //:/currentMessage.message是导致异常的消息!!!
    currentMessage=信封(f,f.子项,系统)
    getChildByRef(f.child)匹配{
    /*
    *只有在失败时才采取行动,如果失败来自目前已知的孩子;
    *UID可防止接收到来自以下儿童的故障:
    *在重新启动前终止,并在重新启动后重新创建
    */
    如果stats.uid==f.uid,则使用case Some(stats)⇒
    ///currentMessage.message未传递给handleFailure!!!
    如果(!actor.supervisorStrategy.handleFailure(this,f.child,f.cause,stats,getAllChildStats))抛出f.cause
    案例部分(统计)⇒
    发布(调试(self.path.toString、clazz(actor),
    从旧子级“+f.child+”(uid=“+stats.uid+”!=“+f.uid+”)中删除失败(“+f.cause+”)
    无案例⇒
    发布(调试(self.path.toString,clazz(actor),“从未知子项“+f.child”删除失败(“+f.cause+”))
    }
    }
    
    真棒的回答,谢谢@gabrielgiussi(+1)——因此我将
    监管策略
    放入自己的Scala类的动机是使它可以在许多参与者(家长)之间重用。看看你的小提琴,难道我不能在我自己的Scala类中扩展
    OneForOneStrategy
    ,并使用你放在其中的相同代码,从而达到我想要的效果吗?然后从每个父级的内部(我想使用这个策略的地方)我可以向类注入一个
    MyOneForOneStrategy
    的实例,然后设置
    override val-supervisorStrategy=MyOneForOneStrategy
    ,这行得通吗?再次感谢!应该有一个很好的理由来扩展监管策略,而不是。您应该可以只定义决策者。你想做什么?为什么需要访问消息、子引用和异常?我想构建健壮的容错逻辑。如果决策者可以跨多个参与者重用,并且可以访问所有三个项目,那么我可以定义决策者