我是Akka(Java lib,v2.3.9)的新手,我正在尝试理解actor依赖性和后备/容错。
假设我有两个演员,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
决定向StatusReport
发送DarthVader
消息时,他:
DarthVader
将正确响应状态报告;或DarthVader
必须故意离线/无响应/无操作在后一种情况下,当DarthVader
假设时(我强调这是为了区分这个用例DarthVader
应该是活着/运行但是在故障/错误状态)为无操作,我不知道如何将其传达回StormTrooper
,如果fizzBuzz#derp()
为无操作,则必须致电DarthVader
。
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最佳实践保持一致。
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
等。)
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
的所有实例/参与者/线程都处于无操作模式,而不仅仅是一个特定实例。
答案 0 :(得分:1)
几乎没有可能的解决方案。首先,您希望从配置中读取DarthVader
处于NoOp
模式,然后创建actor(Typesafe配置将正常工作)。
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);