Akka:交流和处理演员之间的特殊状态(非错误)
Akka: communicating and handling special state (non-error) between actors
我是 Akka(Java lib,v2.3.9)的新手,正在尝试了解 actor 依赖性和 fallback/fault 容忍度。
假设我有两个演员,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
必须 有意 offline/unresponsive/no-op
在后一种情况下,DarthVader
应该是 (我强调这一点是为了将其与 DarthVader
应该是 alive/functioning 但处于 faulty/error 状态)是空操作,我不确定如何将其传达回 StormTrooper
,如果 [=15],他必须简单地调用 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
actors/threads 的所有实例必须处于相同状态(无操作模式 on/off 普遍适用于所有实例),因此我不确定这个解决方案是否符合 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
的所有实例/actors/threads 都处于无操作模式,而不仅仅是一个特定实例。
可能的解决方案很少。首先,您想从配置中读取 DarthVader
是否处于 NoOp
模式,然后创建 actor(Typesafe Config 可以正常工作)。
Config vader = conf.getConfig("vader");
bool isNoOpMode = vader.getBoolean("state");
所以你可以为应用程序设置它。
对于 DarthVader
本人,如您所说,您可以使用聊天解决方案(回复 StormTrooper
),或者将您的第一种方法与 Ask
模式结合使用。您将向 DarthVader
发送报告,并将 return 未来等待 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);
我是 Akka(Java lib,v2.3.9)的新手,正在尝试了解 actor 依赖性和 fallback/fault 容忍度。
假设我有两个演员,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
必须 有意 offline/unresponsive/no-op
在后一种情况下,DarthVader
应该是 (我强调这一点是为了将其与 DarthVader
应该是 alive/functioning 但处于 faulty/error 状态)是空操作,我不确定如何将其传达回 StormTrooper
,如果 [=15],他必须简单地调用 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
actors/threads 的所有实例必须处于相同状态(无操作模式 on/off 普遍适用于所有实例),因此我不确定这个解决方案是否符合 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
的所有实例/actors/threads 都处于无操作模式,而不仅仅是一个特定实例。
可能的解决方案很少。首先,您想从配置中读取 DarthVader
是否处于 NoOp
模式,然后创建 actor(Typesafe Config 可以正常工作)。
Config vader = conf.getConfig("vader");
bool isNoOpMode = vader.getBoolean("state");
所以你可以为应用程序设置它。
对于 DarthVader
本人,如您所说,您可以使用聊天解决方案(回复 StormTrooper
),或者将您的第一种方法与 Ask
模式结合使用。您将向 DarthVader
发送报告,并将 return 未来等待 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);