Akka事件总线教程

时间:2013-04-28 20:41:15

标签: scala akka event-bus

关于如何在akka中使用事件总线,是否有任何好的教程/解释? 我已经阅读了Akka文档,但我发现很难理解如何使用事件总线

2 个答案:

答案 0 :(得分:41)

不确定是否有任何好的教程,但我可以为您提供一个可能的用户案例的快速示例,其中使用事件流可能会有所帮助。但是,在较高级别,事件流是满足应用程序可能具有的发布/订阅类型要求的良好机制。假设您有一个用例,用于更新系统中用户的余额。经常访问余额,因此您决定对其进行缓存以获得更好的性能。更新余额时,您还需要检查并查看用户是否超过其余额的阈值,如果是,请通过电子邮件发送。您不希望缓存丢弃或余额阈值检查直接绑定到主余额更新调用,因为它们可能会很重,并且会降低用户的响应速度。你可以像这样建模那组特定的要求:

//Message and event classes
case class UpdateAccountBalance(userId:Long, amount:Long)
case class BalanceUpdated(userId:Long)

//Actor that performs account updates
class AccountManager extends Actor{
  val dao = new AccountManagerDao

  def receive = {
    case UpdateAccountBalance(userId, amount) =>
      val res = for(result <- dao.updateBalance(userId, amount)) yield{
        context.system.eventStream.publish(BalanceUpdated(userId))
        result                
      }

      sender ! res
  }
}

//Actor that manages a cache of account balance data
class AccountCacher extends Actor{
  val cache = new AccountCache

  override def preStart = {
    context.system.eventStream.subscribe(context.self, classOf[BalanceUpdated])
  }

  def receive = {
    case BalanceUpdated(userId) =>
      cache.remove(userId)
  }
}

//Actor that checks balance after an update to warn of low balance
class LowBalanceChecker extends Actor{
  val dao = new LowBalanceDao

  override def preStart = {
    context.system.eventStream.subscribe(context.self, classOf[BalanceUpdated])
  }

  def receive = {
    case BalanceUpdated(userId) =>
      for{
        balance <- dao.getBalance(userId)
        theshold <- dao.getBalanceThreshold(userId)
        if (balance < threshold)
      }{
        sendBalanceEmail(userId, balance)
      }
  }
}

在此示例中,AccountCacherLowBalanceChecker个参与者都为eventStream事件按类类别订阅了BalanceUpdated。如果此事件是发布到流的事件,则它们将由这两个actor实例接收。然后,在AccountManager中,当余额更新成功时,它会为用户引发BalanceUpdated事件。当发生这种情况时,并行地将该邮件传递到AccountCacherLowBalanceChecker的邮箱,从而导致从缓存中删除余额并检查帐户阈值并可能发送电子邮件

现在,您可以直接将tell (!)调用放入AccountManager以直接与其他两个演员进行通信,但有人可能会认为这可能过于紧密地耦合了这两个“副作用”。余额更新,这些类型的详细信息不一定属于AccountManager。如果你的条件可能导致一些额外的事情(检查,更新等......)纯粹作为副作用(不是核心业务流本身的一部分)需要发生,那么事件流可能是一个好方法解除正在筹集的事件以及可能需要对该事件作出反应的人。

答案 1 :(得分:11)

每个EventBus都有一个ActorSystem。此EventBus称为Event Stream,可以通过调用system.eventStream获取。

ActorSystem使用事件流来处理许多事情,包括logging,发送Dead LettersCluster Events

您还可以将事件流用于您自己的发布/订阅要求。例如,事件流在测试期间可能很有用。对于某些事件(例如记录事件),将Test KittestActor订阅到事件流,您可以expect他们。当某些事情发生时您不会向另一个演员发送消息但您仍然需要在测试中期望该事件时,这可能特别有用。

请注意,事件流只能在一个ActorSystem内使用。如果您正在使用流上发布的远程事件,则默认情况下不会跨越到远程系统(尽管您可以自己添加该支持)。

如果您不想使用事件流,理论上您可以创建单独的EventBus

正在为Akka 2.2制作更好的事件总线文档,因此在this ticket完成后再次检查。