如何透明地将输入元素与输出元素关联

时间:2018-11-29 11:28:13

标签: scala akka akka-stream

我从一些不受控制的外部代码中得到了一个Flow<A, B>(这是花哨的流/图,请参见https://doc.akka.io/api/akka/current/akka/stream/scaladsl/Flow.html)。我需要包装该流程,并对每个输入元素和每个输出元素进行一些处理。我可以通过在其顶部放置一个BidiFlow来轻松实现这一点:

Flow<I, O, Unused> flow = ...; // external source
BidiFlow<I, I, O, O, Unused> bidi = BidiFlow.fromFunctions(i -> preprocess(i), o -> postprocess(o)); // do something on every input and every output
Flow<I, O, Unused> newFlow = bidi.join(flow);

这就是问题所在:要正确地对输出元素o进行后处理,我需要生成该输出元素的输入。由于我无法控制基础流程,因此无法重构它以返回例如输入和输出的元组。而且由于Akka的异步和并行性质,我无法做任何技巧,例如将输入存储在本地线程或静态字段或类似的线程上。

所以我的问题是:是否可以应用Akka Streams魔术以某种方式获取生成输出的输入元素?

2 个答案:

答案 0 :(得分:1)

这是使用GraphDsl,Broadcast和Zip阶段的解决方案。

  val externalFlow: Flow[Int, String, NotUsed] = Flow[Int].map(i => i.toString + "-external")

  def zipInAndOut[I, O](flow: Flow[I, O, NotUsed]): Flow[I, (I, O), NotUsed] = {
    Flow.fromGraph(GraphDSL.create() { implicit b =>
      import GraphDSL.Implicits._
      val broadcast = b.add(Broadcast[I](2))
      val zip = b.add(Zip[I, O])
      val theFlow = b.add(flow)
      broadcast.out(0) ~> zip.in0
      broadcast.out(1) ~> theFlow ~> zip.in1
      new FlowShape(broadcast.in, zip.out)
    })
  }
  Source
    .fromIterator(() => (1 until 10).iterator)
    .via(zipInAndOut(externalFlow))
    .runWith(Sink.foreach(println))

打印

(1,1-external)
(2,2-external)
(3,3-external)
(4,4-external)
(5,5-external)
(6,6-external)
(7,7-external)
(8,8-external)
(9,9-external)

答案 1 :(得分:0)

您可以使用图形Api。您可以将输入广播到两个流程,一个流程进行处理,另一个流程绕过您的ID。 las任务应该是这些流程的压缩。看一下Akka Streams / HTTP: Get original request from response。也许可以帮上忙。