akka系统 - 在actor之间执行通用逻辑的最佳实践

时间:2016-05-24 18:04:02

标签: scala akka actor

我对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之间进行通信。

您怎么看?

1 个答案:

答案 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"
  }
}