【问题标题】:How to return early in a pattern match of akka actor receive如何在 akka actor 的模式匹配中尽早返回接收
【发布时间】:2017-10-16 10:47:04
【问题描述】:

在这个微不足道的问题上尝试了谷歌搜索变体,但没有得到答案......

基本上我的接收方法中有一个模式匹配。 在某些情况下,我想尽早从接收处理中中断

    override def receive = {
        case blah => {
          ... preflight code
          if (preflight failed) {
            sender() ! errorMSG 
            "break" or "return" here // get error "method receive has a return statement ; needs result type - 
// I tried adding Unit to the receive and return statements
          }
          ... more code
           ....

          if (something happened) {
            sender() ! anotherErrorMSG
            "break" or "return" here
          }
          ...
       }
       case foo => {...}
       case bar => {...}
     } // end receive

【问题讨论】:

    标签: scala syntax akka partialfunction


    【解决方案1】:

    请参阅this discussion of return's semantics 并记住,receive 返回一个 PartialFunction[Any, Unit],然后在 receive 返回后对其进行评估。简而言之,没有办法早退。

    Ömer Erden 抛出异常并使用 actor 监督的解决方案有效(事实上,抛出异常及其所有开销基本上是可靠地提前结束计算的唯一方法),但如果您需要任何状态从消息传递到消息,你需要 Akka 持久性。

    如果您不想像 chunjef 的解决方案那样嵌套 if-else,您可以使用 context.become 和 stash 创建一些意大利面条式的代码。

    但最好的解决方案可能是让可能失败的东西是它们自己的函数,具有 Either 结果类型。请注意,scala 2.12 中的 Either API 比以前的版本好很多。

    import scala.util.{ Either, Left, Right }
    
    type ErrorMsg = ...
    type PreflightSuccess = ... // contains anything created in preflight that you need later
    type MoreCodeSuccess = ... // contains anything created in preflight or morecode that you need later
    
    def preflight(...): Either[ErrorMsg, PreFlightSuccess] = {
      ... // preflight
      if (preflight failed)
        Left(errorMsg)
      else
        Right(...) // create a PreflightSuccess
    }
    
    def moreCode1(pfs: PreFlightSuccess): Either[ErrorMsg, MoreCodeSuccess] = {
      ... // more code
      if (something happened)
        Left(anotherErrorMSG)
      else
        Right(...) // create a MoreCodeSuccess
    }
    
    def moreCode2(mcs: MoreCodeSuccess): Either[ErrorMsg, Any] = {
      ... // more code, presumably never fails
      Right(...)
    }
    
    override def receive = {
      case blah =>
        val pf = preflight(...)
        val result = pf.map(morecode1).joinRight.map(moreCode2).joinRight // only calls morecode1 if preflight succeeded, and only calls morecode2 if preflight and morecode1 succeeded
        result.fold(
          { errorMsg => sender ! errorMsg },
          ()
        )
      case foo => ...
      case bar => ...
    }
    

    这是否比嵌套的 if-else 更可取是一个品味问题......

    【讨论】:

    • 你也可以用 flatMap(...) 替换 map(...).joinRight,现在我看了一下。
    【解决方案2】:

    这可能不是您问题的确切答案,但在您的情况下,添加 supervisor 演员将是更好的解决方案。在 Akka 监督模型中,说服您处理监督参与者的异常,而不是将错误消息发送回发送者。

    这种方法为您带来了一个容错模型,并且您可以在任何您想要的行抛出异常(这解决了您当前的问题),您的主管 Actor 将通过重新启动、恢复或阻止儿童演员。

    请查看link

    【讨论】:

      猜你喜欢
      • 2018-09-30
      • 2016-07-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 2020-04-15
      • 1970-01-01
      相关资源
      最近更新 更多