Java Akka:在参与者之间通信和处理特殊状态(非错误)
我对Akka(Javalib,v2.3.9)是一个全新的概念,我试图理解参与者依赖性和回退/容错 假设我有两名演员,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
冲锋队
和达特瓦德
:
// 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);