Akka Streams - 跳过FlowShape

时间:2017-11-09 15:08:15

标签: scala akka-stream

我有以下图表。

inflateFlow阶段,我检查是否已在DB中处理了请求。如果已经处理完消息,我想返回MsgSuccess而不是RequestProcess,但下一个FlowShape将不接受,它需要RequestProcess。有没有办法从flowInflate跳到flowWrap而无需在任何地方添加Either

GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
  import GraphDSL.Implicits._

  val flowInflate = builder.add(wrapFunctionInFlowShape[MsgRequest, RequestProcess](inflateFlow))
  val flowProcess = builder.add(wrapFunctionInFlowShape[RequestProcess, SuccessProcess](convertFlow))
  val flowWrite = builder.add(wrapFunctionInFlowShape[SuccessProcess, SuccessProcess](writeFlow))
  val flowWrap = builder.add(wrapFunctionInFlowShape[SuccessProcess, MsgSuccess](wrapFlow))

  flowInflate ~> flowProcess ~> flowWrite ~> flowWrap

  FlowShape(flowInflate.in, flowWrap.out)
}

def wrapFunctionInFlowShape[Input, Output](f: Input => Output): Flow[Input, Output, NotUsed] = {
  Flow.fromFunction { input =>
    f(input)
  }
}

//check for cache
def inflateFlow(msgRequest: MsgRequest): Either[RequestProcess, MsgSuccess] = {
  val hash: String = hashMethod(msgRequest)
  if(existisInDataBase(hash))
    Right(MsgSuccess(hash))
  else
    Left(inflate(msgRequest))
}

def convertFlow(requestPorocess: RequestPocess): SuccessProcess = {}//process the request}
def writeFlow(successProcess: SuccessProcess): SuccessProcess = {}//write to DB}
def wrapFlow(successProcess: SuccessProcess): MsgSuccess = {}//wrap and return the message}

1 个答案:

答案 0 :(得分:1)

您可以使用分区在流中定义备用路径。在您的情况下,PartitionWith项目中的Akka Stream Contrib阶段可能会有所帮助。与标准Akka Streams API中的Partition阶段不同,PartitionWith允许输出类型不同:在您的情况下,输出类型为RequestProcessMsgSuccess

首先,要使用PartitionWith,请将以下依赖项添加到build.sbt

libraryDependencies += "com.typesafe.akka" %% "akka-stream-contrib" % "0.8"

其次,用分区替换inflateFlow

def split = PartitionWith[MsgRequest, RequestProcess, MsgSuccess] { msgRequest =>
  val hash = hashMethod(msgRequest)
  if (!existisInDataBase(hash))
    Left(inflate(msgRequest))
  else
    Right(MsgSuccess(hash))
}

然后将该阶段合并到您的图表中:

val flow = Flow.fromGraph(GraphDSL.create() { implicit builder: GraphDSL.Builder[NotUsed] =>
  import GraphDSL.Implicits._

  val pw = builder.add(split)
  val flowProcess = builder.add(wrapFunctionInFlowShape[RequestProcess, SuccessProcess](convertFlow))
  val flowWrite = builder.add(wrapFunctionInFlowShape[SuccessProcess, SuccessProcess](writeFlow))
  val flowWrap = builder.add(wrapFunctionInFlowShape[SuccessProcess, MsgSuccess](wrapFlow))

  val mrg = builder.add(Merge[MsgSuccess](2))

  pw.out0 ~> flowProcess ~> flowWrite ~> flowWrap ~> mrg.in(0)
  pw.out1 ~> mrg.in(1)

  FlowShape(pw.in, mrg.out)
})

如果在数据库中找不到传入的MsgRequest并将其转换为RequestProcess,则该消息将通过您的原始流路径。如果传入的MsgRequest在数据库中并解析为MsgSuccess,则它会绕过流中的中间步骤。在这两种情况下,生成的MsgSuccess消息都会从两个备用路径合并到一个流出口。