Java Akka:在参与者之间通信和处理特殊状态(非错误)

Java Akka:在参与者之间通信和处理特殊状态(非错误),java,akka,actor,Java,Akka,Actor,我对Akka(Javalib,v2.3.9)是一个全新的概念,我试图理解参与者依赖性和回退/容错 假设我有两名演员,冲锋队和达特瓦德: // Groovy pseudo-code class StatusReport { private final Report report StatusReport(Input report) { super() this.report = deepClone(report) } Input

我对Akka(Javalib,v2.3.9)是一个全新的概念,我试图理解参与者依赖性和回退/容错

假设我有两名演员,
冲锋队
达特瓦德

// Groovy pseudo-code
class StatusReport {
    private final Report report

    StatusReport(Input report) {
        super()
        this.report = deepClone(report)
    }

    Input getReport() {
        deepClone(this.report)
    }
}

class StormTrooper extends UntypedActor {
    ActorRef lordVader  // Injected with reference to DarthVader

    @Override
    void onReceive(Object message) {
        if(message instanceof PerformReport) {
            PerformReport pr = message as PerformReport
            Report report = ReportUtils.generateReport(pr.config)
            StatusReport statusReportMsg = new StatusReport(report)
            lordVader.tell(statusReportMessage, ...)
        }
    }
}

class DarthVader extends UntypedActor {
    @Override
    void onReceive(Object message) {
        if(message instanceof StatusReport) {
            // Do something meaningful with the status report.
        }
    }
}
在某些情况下,
DarthVader
基本上是空的,应该是禁止操作的。也就是说:
StormTrooper
决定向
DarthVader
发送
StatusReport
消息时,他:

  • 可能已配置为活动且功能正常,在这种情况下,
    DarthVader
    将正确响应状态报告;或
  • 用户可能已采取措施(通过配置),使得
    DarthVader
    必须有意地离线/无响应/无操作
  • 在后一种情况下,当
    DarthVader
    被假定为无操作时(我强调这一点是为了将其与
    DarthVader
    被假定为活动/运行但处于故障/错误状态时的用例区分开来),我不确定如何将其传达给
    冲锋队
    ,他们必须简单地呼叫
    fizzBuzz#derp()
    如果
    DarthVader
    为无操作

    解决方案#1:基于状态的无操作检测 我不确定的是
    DarthVader
    actors/threads的所有实例必须处于相同的状态(没有一种操作模式是开/关的,普遍适用于所有实例),因此我不确定该解决方案是否符合Akka最佳实践

    解决方案2:抛出特殊异常 但使用异常来控制流量通常是不允许的,甚至可能触发内置的Akka主管行为(对异常的反应可能导致Akka重新启动冲锋队等)

    解决方案#3:返回响应消息 但这似乎是一个麻烦的、喋喋不休的解决方案


    所以我问:
    DarthVader
    StormTrooper
    指示它处于无操作模式,从而
    StormTrooper
    知道调用
    fizzBuzz.derp()
    的最佳方式是什么?请记住,如果
    DarthVader
    处于无操作模式,则
    DarthVader
    的所有实例/参与者/线程都处于无操作模式,而不仅仅是一个特定实例。

    几乎没有可能的解决方案。首先,您想从config中读取如果
    DarthVader
    处于
    NoOp
    模式,则创建actor(类型安全配置将正常工作)

    因此,您可以为应用程序通用地设置它

    对于
    DarthVader
    本人,正如您所说,您可以使用聊天解决方案(响应
    StormTrooper
    ),或者使用您的第一种方法与
    Ask
    模式结合使用。您将向
    DarthVader
    发送报告,并返回Future,该Future将等待
    DarthVader
    响应

    Timeout timeout = new Timeout(Duration.create(5, "seconds"));
    Future<Object> future = Patterns.ask(lordVader, statusReportMsg, timeout);
    
    class StormTrooper extends UntypedActor {
        ActorRef lordVader  // Injected with reference to DarthVader
    
        @Override
        void onReceive(Object message) {
            if(message instanceof PerformReport) {
                try {
                    PerformReport pr = message as PerformReport
                    Report report = ReportUtils.generateReport(pr.config)
                    StatusReport statusReportMsg = new StatusReport(report)
                    lordVader.tell(statusReportMessage, ...)
                } catch(DarthVaderNoOpException dvnoExc) {
                    fizzBuzz.derp()
                }
            }
        }
    }
    
    class DarthVader extends UntypedActor {
        boolean isNoOpMode = false
    
        @Override
        void onReceive(Object message) {
            if(message instanceof StatusReport) {
                if(!isNoOpMode) {
                    // Do something meaningful with the status report.
                } else {
                    throw new DarthVaderNoOpException()
                }
            }
        }
    }
    
    class StormTrooper extends UntypedActor {
        ActorRef lordVader  // Injected with reference to DarthVader
    
        @Override
        void onReceive(Object message) {
            if(message instanceof PerformReport) {
                PerformReport pr = message as PerformReport
                Report report = ReportUtils.generateReport(pr.config)
                StatusReport statusReportMsg = new StatusReport(report)
                lordVader.tell(statusReportMessage, ...)
            } else if(message instanceof DarthVaderNoOp) {
                fizzbuzz.derp()
            }
        }
    }
    
    class DarthVader extends UntypedActor {
        ActorRef stormTrooper
        boolean isNoOpMode = false
    
        @Override
        void onReceive(Object message) {
            if(message instanceof StatusReport) {
                if(!isNoOpMode) {
                    // Do something meaningful with the status report.
                } else {
                    DarthVaderNoOp noOpMsg = new DarthVaderNoOp()
                    stormTrooper.tell(noOpMsg, ...)
                }
            }
        }
    }
    
    Config vader = conf.getConfig("vader");
    bool isNoOpMode = vader.getBoolean("state");
    
    Timeout timeout = new Timeout(Duration.create(5, "seconds"));
    Future<Object> future = Patterns.ask(lordVader, statusReportMsg, timeout);
    
    final ExecutionContext ec = system.dispatcher();
    
    future.onComplete(new OnComplete<VaderResponse>() {
      public void onComplete(Throwable failure, VaderResponse result) {
        if (failure != null) {
          // Derp
        } else {
          // Report acknowledged
        }
      }
    }, ec);