【问题标题】:Akka: communicating and handling special state (non-error) between actorsAkka:在参与者之间通信和处理特殊状态(非错误)
【发布时间】:2015-04-23 14:57:28
【问题描述】:

我是 Akka 的新手(Java lib,v2.3.9),我正在尝试了解参与者依赖和回退/容错。

假设我有两个演员,StormTrooperDarthVader

// 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 本质上是 NULL 并且应该是空操作。即:当StormTrooper决定向DarthVader发送StatusReport消息时,他:

  1. 可能已配置为活动和功能,在这种情况下DarthVader 将正确响应状态报告;或
  2. 用户可能已采取措施(通过配置),使得DarthVader 必须有意离线/无响应/无操作

在后一种情况下,当DarthVader假设(我强调这一点是为了与DarthVader 应该处于活动状态/正常工作但处于故障/错误状态的用例区分开来) 是无操作的,我不知道如何将它传达给StormTrooper,如果DarthVader 是无操作的,他必须简单地调用fizzBuzz#derp()

解决方案 #1:基于状态的无操作检测

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

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

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.
            }

            // Obviosuly, if we are in no-op mode, do nothing.
        }
    }
}

我的不确定性是 DarthVader 演员/线程的所有实例必须处于相同状态(无操作模式开/关普遍适用于所有这些),所以我不确定这个解决方案是否甚至符合 Akka 最佳实践也是可行的。

解决方案 #2:抛出专门的异常

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()
            }
        }
    }
}

但是使用异常来控制流是一个普遍的禁忌,甚至可能触发内置的 Akka 主管行为(对异常做出反应可能会导致 Akka 重启StormTrooper 等)。

解决方案 #3:发回响应消息

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, ...)
            }
        }
    }
}

但这似乎是一个繁琐、冗长的解决方案。

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

【问题讨论】:

    标签: java akka actor


    【解决方案1】:

    几乎没有可能的解决方案。首先,您想从配置中读取DarthVader 是否处于NoOp 模式,然后创建actor(Typesafe Config 可以正常工作)。

    Config vader = conf.getConfig("vader");
    bool isNoOpMode = vader.getBoolean("state");
    

    因此您可以为应用程序设置它。

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

    Timeout timeout = new Timeout(Duration.create(5, "seconds"));
    Future<Object> future = Patterns.ask(lordVader, statusReportMsg, timeout);
    

    请注意,您不是要调用Await 方法,而是要处理onComplete 内部的响应,例如:

    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);
    

    【讨论】:

      猜你喜欢
      • 2011-07-26
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 1970-01-01
      • 2019-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多