【发布时间】:2015-04-23 14:57:28
【问题描述】:
我是 Akka 的新手(Java lib,v2.3.9),我正在尝试了解参与者依赖和回退/容错。
假设我有两个演员,StormTrooper 和 DarthVader:
// 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消息时,他:
- 可能已配置为活动和功能,在这种情况下
DarthVader将正确响应状态报告;或 - 用户可能已采取措施(通过配置),使得
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, ...)
}
}
}
}
但这似乎是一个繁琐、冗长的解决方案。
所以我问:DarthVader 向StormTrooper 表明它处于无操作模式的最佳方式是什么,以便StormTrooper 知道调用fizzBuzz.derp()?请记住,如果DarthVader 处于无操作模式,则DarthVader 的所有实例/参与者/线程都处于无操作模式,而不仅仅是一个特定的实例。
【问题讨论】: