在CRUD Web应用程序中使用Akka actor

时间:2012-12-19 13:09:27

标签: scala playframework-2.0 akka

我正在使用Play编写一个用Scala编写的Web应用程序!框架和Akka。代码基本上是这样组织的:播放控制器向Akka演员发送消息。反过来,参与者与持久层交谈,该层提取数据库访问。在应用程序中使用这些组件的典型示例:

class OrderController(orderActor: ActorRef) extends Controller {
  def showOrders(customerId: Long) = {
    implicit request => Async {
      val futureOrders = orderActor ? FindOrdersByCustomerId(id)

      // Handle the result, showing the orders list to the user or showing an error message.
    }
  }
}

object OrderActor extends Actor {
  def receive = {
    case FindOrdersByCustomerId(id) => 
      sender ! OrderRepository.findByCustomerId(id)
    case InsertOrder(order) =>
      sender ! OrderRepository.insert(order)
      //Trigger some notification, like sending an email. Maybe calling another actor.
  }
}

object OrderRepository {
  def findByCustomerId(id: Long): Try[List[Order]] = ???
  def insert(order: Order): Try[Long] = ???
}

正如您所看到的,这是基本的CRUD模式,就像您在其他语言和框架中看到的那样。查询会传递给下面的层,当应用程序从数据库中获取结果时,该结果将返回到达UI。唯一相关的区别是使用actor和异步调用。

现在,我对演员的概念很新,所以我还没有完全理解。但是,从我读过的内容来看,并不是演员应该如何使用。但请注意,在某些情况下(例如,在插入订单时发送电子邮件),我们确实需要真正的异步消息传递。

所以,我的问题是:以这种方式使用演员是个好主意吗?在Scala中编写CRUD应用程序有哪些替代方法,利用Futures和Akka的其他并发功能?

2 个答案:

答案 0 :(得分:5)

尽管基于actor的并发性并不适合开箱即用的事务操作,但是如果你能够很好地使用持久层,那么这并不会阻止你以这种方式使用actor。如果你可以保证插入(写入)是原子的,那么你可以安全地让一个演员池为你做这件事。通常,数据库具有线程安全读取,因此查找也应该按预期工作。除此之外,如果 insert 不是线程安全的,您可以只使用一个WriteActor专门用于写操作,并且消息的顺序处理将确保您的原子性。

答案 1 :(得分:2)

要注意的一件事是,一个actor一次处理一条消息,在这种情况下会有相当的限制。您可以使用routers来使用演员池。

您的示例定义了存储库的阻塞api,这可能是您可以执行的唯一操作,具体取决于您的数据库驱动程序。如果可能的话,你也应该去找一个异步api,即返回Futures。然后在演员中,你将pipe未来的结果发送给发件人。