Akka流和事务边界

时间:2016-11-12 13:47:56

标签: transactions akka akka-stream reactive-streams

当我们有一些需要以原子方式处理的项目时,我仍然在掌握Akka流概念并试图了解如何将它们映射到场景。假设我们有一个由多个项目组成的采购订单,我们需要对每个项目应用一些处理,然后将它们合并回一个值。这样的工作流程是否应该成为自己独立的流(或子流),一旦采购订单被完全处理,该流将被关闭?即每个采购订单都会启动一个新流?或者我有一系列永不停止的采购订单?但如果是这样,我不会有混合不同订单的采购订单的问题吗?

换句话说,我想要实现的是处理不同工作流程的隔离,并想知道Akka流是否提供了良好匹配。

1 个答案:

答案 0 :(得分:2)

直接回答您的问题:可以创建一个流,“将一些处理应用于每个项目,然后将它们合并回一个值”。

使用示例代码开发示例:

case class Item(itemId : String)

case class PurchaseOrder(orderId : String, items : Seq[Item])

val purchaseOrder : PurschaseOrder = ???

如果我们想用流来处理项目,虽然减少的确切性质在问题上是模棱两可的,所以我不会定义如何实现折叠:

type ProcessOutput = ???

def processItem(item : Item) : ProcessOutput = ???

val combinedResult : Future[CombinedResult] = 
  Source.fromIterator( purchaseOrder.items.toIterator )
        .via(Flow[Item] map processItem)
        .to(Sink.fold[ProcessOutput](???)(???) )
        .run()

间接回答你的问题,

考虑期货优先

当需要背压时,Akka流非常有用。当您连接到外部数据源时,背压很常见,因为bp允许您的应用程序确定数据流传输到您的速度,因为您负责不断发出更多数据需求的信号。

如果您在问题中提出,则无需广播需求,and incur the inherent overhead此类通信需要。您已经拥有了一系列商品,因此没有人向...发送需求。

相反,我认为期货是您描述的案例的最佳方式:

def futProcess(item : Item)(implicit ec : ExecutionContext) = 
  Future { processItem(item) } 

// same output type as the stream run 
val combinedResults : Future[CombinedResult] = 
  Future.sequence{ purchaseOrder.items map futProcess }
        .map{ _ fold[ProcessOutput](???)(???) }

你可以获得更好的性能,减少拥有完整ActorSystem的复杂性,以及与流完全相同的结果......