我对akka演员系统很陌生,并且正在徘徊在演员中执行常见逻辑的最佳实践。 所以这是一个例子:
我有以下演员:
class MyActor @Inject()(eventBus: EventBus) extends Actor{
eventBus.subscribe(context.self, Topics.TimeoffPolicy)
override def receive: Receive = {
case Foo(name:String) => {
//Need to execute foo related logic, and then Bar related logic
}
case Bar(name:String) => {
//Need to execute bar related logic
}
case a: Any => log.warning(f"unknown message actor ${a.toString}")
}
}
因此,一个选项是将常用逻辑提取到方法中,并在处理Foo时调用它,如下所示:
class MyActor @Inject()(eventBus: EventBus) extends Actor{
eventBus.subscribe(context.self, Topics.TimeoffPolicy)
override def receive: Receive = {
case Foo(name:String) => {
foo(name)
bar(name)
}
case Bar(name:String) => {
bar(name)
}
case a: Any => log.warning(f"unknown message actor ${a.toString}")
}
}
其他选择是向自己发送消息:
class MyActor @Inject()(eventBus: EventBus) extends Actor{
eventBus.subscribe(context.self, Topics.TimeoffPolicy)
override def receive: Receive = {
case Foo(name:String) => {
foo()
self ! Bar(name)
}
case Bar(name:String) => {
bar(name)
}
case a: Any => log.warning(f"unknown message actor ${a.toString}")
}
}
在这里,发送消息并将逻辑封装在每个消息处理中都是有意义的,但我想将一般逻辑提取到方法并调用它的错误修剪就更少了。推荐什么?
在actor之间有一个共同逻辑的情况下,一个选项是通过事件总线向另一个actor发送消息来调用,所以actor1将执行foo,另一个将执行bar。 第二个选项是将相同的逻辑提取到另一个类中,并将该类注入到两个actor中,因此,为了执行foo和bar,不会在actor之间进行通信。
您怎么看?
答案 0 :(得分:1)
这两种方法对我来说都是合法的,我会根据是否在共享逻辑中调用其他actor来选择其中一种。基本上,同步逻辑可以通过提取方法完美地重用,异步逻辑将需要将消息传递回自己。
来自self
的消息也绝对是首选从Future
回调发送的(实际上,这是唯一正确的方法,以免混淆演员任务的执行顺序)和在预定的活动中。
这是一个说明同步方法的片段:
class MyActor extends Actor with ActorLogging {
def receive = {
case Foo(foo) =>
doSomeFooSpecificWork()
logFooOrBar()
sender() ! "foo done"
case Bar =>
logFooOrBar()
sender() ! "bar done"
}
def logFooOrBar() = log.debug("A common message is handled")
}
以下是我为异步编写的内容:
import akka.pattern.{ask, pipe}
class MyActor extends Actor {
val logger = context.actorOf(Props[DedicatedLogger])
def receive = {
case Foo(foo) =>
doSomeFooSpecificWork()
loggerActor ? LogFooOrBar(sender(), foo) pipeTo self
case Bar(bar) =>
loggerActor ? LogFooOrBar(sender(), bar) pipeTo self
case LoggedFoo(reportTo, foo) => reportTo ! "foo done"
case LoggedBar(reportTo, bar) => reportTo ! "bar done"
}
}