[英]Akka: communicating and handling special state (non-error) between actors
I am brand new to Akka (Java lib, v2.3.9) and am trying to understand actor dependency and fallback/fault tolerance. 我是Akka的新手(Java lib,v2.3.9),并试图了解参与者的依存关系和后备/容错能力。
Say I have two actors, StormTrooper
and DarthVader
: 假设我有两个演员,
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.
}
}
}
Under some circumstances, DarthVader
is essentially NULL and should be a no-op. 在某些情况下,
DarthVader
本质上为NULL,并且应该为空。 That is: when StormTrooper
decides to send a StatusReport
message to DarthVader
, he: 即:当
StormTrooper
决定将StatusReport
消息发送给DarthVader
,他:
DarthVader
will correctly respond to the status report; DarthVader
将正确响应状态报告; or DarthVader
must be intentionally offline/unresponsive/no-op DarthVader
必须故意脱机/无响应/无操作 In the latter case when DarthVader
is supposed (I emphasize this to distinguish this from a use case when DarthVader
is supposed to be alive/functioning but is in a faulty/error state) to be no-op, I'm not sure how to communicate that back to StormTrooper
, who must simply call fizzBuzz#derp()
if DarthVader
is no-op. 在后一种情况下,当假设使用
DarthVader
时(我强调这点是为了与在DarthVader
应该处于活动状态/功能正常但处于故障/错误状态的用例区别开)时,我不确定如何将其传达给StormTrooper
,如果DarthVader
是no-op,则必须简单地调用fizzBuzz#derp()
。
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.
}
}
}
My uncertainty here is that ALL instances of DarthVader
actors/threads must be in the same state (no-op mode being on/off applies universally to all of them), and so I'm not sure if this solution is even viable of in keeping with Akka best practices. 我的不确定性是
DarthVader
actor /线程的所有实例都必须处于同一状态(打开/关闭no-op模式普遍适用于所有实例),因此我不确定该解决方案是否适用于遵守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()
}
}
}
}
But using exceptions to control flow is a general no-no, and may even trigger built-in Akka supervisor behavior (reacting to exceptions may cause Akka to restart StormTrooper
, etc.). 但是使用异常来控制流是通常的
StormTrooper
,甚至可能触发内置的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, ...)
}
}
}
}
But this seems like a cumbersome, chatty solution. 但这似乎是一个麻烦的,健谈的解决方案。
So I ask: what's the best way for DarthVader
to indicate to StormTrooper
that it's in no-op mode, such that StormTrooper
knows to call fizzBuzz.derp()
? 所以我问:什么是最好的方式
DarthVader
来指示StormTrooper
,它在无操作模式,使得StormTrooper
知道调用fizzBuzz.derp()
Remember that if DarthVader
is in no-op mode, all instances/actors/threads of DarthVader
are in no-op mode, not just one particular instance. 请记住,如果
DarthVader
是在无操作模式,所有实例/演员/线程DarthVader
是无操作模式,不只是一个特定的实例。
There is few possible solutions. 几乎没有解决方案。 First, you want to read if
DarthVader
is in NoOp
mode from config then actor is created (Typesafe Config will work fine). 首先,您想从配置读取
DarthVader
是否处于NoOp
模式,然后创建actor(Typesafe Config可以正常工作)。
Config vader = conf.getConfig("vader");
bool isNoOpMode = vader.getBoolean("state");
So you can set it universaly for the application. 因此,您可以为应用程序设置通用性。
For DarthVader
himself, as you said, you can do chatty solution (respond to StormTrooper
), or utilize your first approach with conjuction with Ask
pattern. 正如您所说,对于
DarthVader
本人而言,您可以进行健谈解决方案(响应StormTrooper
),或者将第一种方法与Ask
模式结合使用。 You will send report to DarthVader
and will return Future which will await for DarthVader
response. 您将把报告发送给
DarthVader
,然后返回Future,等待DarthVader
回应。
Timeout timeout = new Timeout(Duration.create(5, "seconds"));
Future<Object> future = Patterns.ask(lordVader, statusReportMsg, timeout);
Please note, you do not want to call Await
method, but to handle response inside onComplete
, for example: 请注意,您不想调用
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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.