有状态的流动实现最终状态

时间:2017-08-22 09:42:24

标签: scala akka akka-stream dataflow

我正在尝试实施akka流过滤器流程,该流程收集有关已处理数据的统计信息并实现生成的统计信息。

class SFilter[A](p: A => Boolean) extends GraphStage[FlowShape[A, A]] {
  val in = Inlet[A]("SFilter.in")
  val out = Outlet[A]("SFilter.out")
  val shape = FlowShape.of(in, out)
  override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
    new GraphStageLogic(shape) {
      var positive: Long = 0
      var negative: Long = 0
      setHandler(in, new InHandler {
        override def onPush(): Unit = {
          val elem = grab(in)
          if (p(elem)) { 
            push(out, elem)
            positive += 1
          } else { 
            pull(in)
            negative += 1
          }
        }
      })
      setHandler(out, new OutHandler {
        override def onPull(): Unit = {
          pull(in)
        }
      })
    }
}

到目前为止一切顺利,但我希望我的SFilter[A]属于Flow[A,A,(Long,Long)]类型。如何在共同点结束时实现(positive,negative)

2 个答案:

答案 0 :(得分:0)

您无法实现Tuple2[Long, Long],因为这些Longs将取决于正在运行的流本身。但是,您可以实现Future[Tuple2[Long, Long]],然后在流完成时完成。{/ p>

编辑:您希望以不同的方式命名自定义阶段,以便区分普通过滤器和SFilter。

答案 1 :(得分:0)

感谢Viktor Klang的建议,我能够实施以下解决方案:

class SFilter[A](p: A => Boolean) extends GraphStageWithMaterializedValue[FlowShape[A,A],Future[(Long,Long)]] {
  val in = Inlet[A]("SFilter.in")
  val out = Outlet[A]("SFilter.out")
  val shape = FlowShape.of(in, out)
  override def createLogicAndMaterializedValue(inheritedAttributes: Attributes) = {
    val result = Promise[(Long,Long)]()
    val logic = new GraphStageLogic(shape) {
      var positive: Long = 0
      var negative: Long = 0
      setHandler(in, new InHandler {
        override def onPush(): Unit = {
          val elem = grab(in)
          if (p(elem)) { 
            push(out, elem)
            positive += 1
          } else { 
            pull(in)
            negative += 1
          }
        }
        override def onUpstreamFinish(): Unit = {
          result.success( (positive,negative) )
          completeStage()
        }
      })
      setHandler(out, new OutHandler {
        override def onPull(): Unit = {
          pull(in)
        }
      })
      (logic, result.future)
    }
}