0

有几个用例如下。

1) createUserAPI 调用是通过前端进行的。一旦这个调用成功,意味着数据成功保存到db,返回成功到前端。API 合约在前端和后端之间结束。

2)现在后端需要生成并触发CreateUser将用户创建到第三方应用程序中的事件(例如,我们可以说它将 createUser 到外部授权系统中)。这是完全异步的后台类型进程,客户端既不知道也不等待此 API 的成功或失败。CreateUser但是必须记录对此事件的所有调用以及它的失败或成功,以用于审计和补救(在失败的情况下)目的。

第一种方法是我们Future为这些异步事件(应用程序的其余部分大量使用)设计基于异步 API,将Futures传入async事件和结果的成功/失败记录到数据库中。

第二种方法是我们使用 Akka 并为这些事件设置单独的参与者(例如CreateUser,一个示例)。这可能看起来像

class CreateUserActor extends Actor {

def receive = {
case CreateUserEvent(user, role) =>
  val originalSender = sender
  val res = Future {
    blocking {
    //persist CreateUserEvent to db

      SomeService.createUser(user, role)
    }
  }
  res onComplete {
    case Success(u) => //persist success to db
    case Failure(e) => //persist failure to db
  }

}

第三种方法使用Akka Persistence,因此事件的持久化可以通过事件源日志开箱即用地发生。然而,事件成功或失败的第二次持久性将是手动的(为其编写代码)。虽然这第三种方法看起来很有希望,但它可能不会得到很好的回报,因为现在我们依赖 Akka 持久性来持久化事件,持久化事件成功/失败的第二个要求仍然是手动的,现在必须维护一个更多的存储(持久化日志等)所以不确定我们是否在这里买了很多东西?

第二种方法需要为这两种情况(传入事件和事件结果)编写持久代码。

第一种方法可能看起来不太有希望。

尽管听起来可能像这样,但我并不打算提出一个听起来像“基于意见”的问题,而是试图就上述方法或其他任何可能适合此处的方法的优缺点提供真正的建议。

仅供参考:此特定应用程序是在播放服务器上运行的播放应用程序,因此使用 Actors 不是问题。

4

1 回答 1

2

由于这是一个 Play 应用程序,您可以使用 Akka 事件流来发布事件,而无需引用后端工作角色。

例如,使用以下内容actors/Subscriber.scala

package actors

import akka.actor.Actor
import model._

class Subscriber extends Actor {
  context.system.eventStream.subscribe(self, classOf[DomainEvent])

  def receive = {
    case event: DomainEvent =>
    println("Received DomainEvent: " + event)
  }
}

...以及类似的内容model/events.scala

package model

trait DomainEvent

case class TestEvent(message: String) extends DomainEvent

...您的控制器可以像这样发布 TestEvent:

object Application extends Controller {
  import akka.actor.Props
  import play.libs.Akka

  Akka.system.actorOf(Props(classOf[actors.Subscriber]))  // Create the backend actor

  def index = Action {
    Akka.system.eventStream.publish(model.TestEvent("message"))  // publish an event
    Ok(views.html.index("Hi!"))
  }
}
于 2014-07-03T22:05:20.817 回答