Akka流-在使用合并时触发元素流

时间:2018-10-03 00:28:17

标签: akka-stream

我试图通过Web套接字创建一个服务,该服务将接受JSON,然后在被触发时发出最后接收的值。我的示例代码是:

import akka.actor.ActorSystem
import akka.stream.scaladsl.{Broadcast, Flow, GraphDSL, ZipWith}
import akka.stream._
import play.api.libs.json._
import play.api.mvc.WebSocket
import play.core.server.{AkkaHttpServer, Server, ServerConfig}
import play.api.routing.sird._
import scala.io.StdIn

object Trigger extends App {

    import GraphDSL.Implicits._
    implicit val system: ActorSystem = ActorSystem("trigger")
    implicit val materializer: ActorMaterializer = ActorMaterializer.create(system)

    val triggerFilter = Flow[JsValue].filter(json => (json \ "trigger").isDefined)
    val dataFilter = Flow[JsValue].filter(json => (json \ "trigger").isEmpty)

    val triggerBatching = Flow[JsValue].conflate((acc, elem) => elem)
    val dataBatching = Flow[JsValue].conflate((acc, elem) => elem)

    val partial = GraphDSL.create() { implicit builder =>
        val B = builder.add(Broadcast[JsValue](outputPorts = 2))
        val zip = builder.add(ZipWith((msg: JsValue, trigger: JsValue) => msg))

        B ~> dataFilter.async    ~> dataBatching.async    ~> zip.in0
        B ~> triggerFilter.async ~> triggerBatching.async ~> zip.in1

        FlowShape(B.in, zip.out)
    }.named("partial")

    val flow = Flow.fromGraph(partial)

    val BufferSize: Int = 100
    val Port: Int = 9001

    val server: Server = AkkaHttpServer.fromRouterWithComponents(ServerConfig(
        port = Some(Port),
        address = "127.0.0.1"
    )) { components => {
        case GET(p"/ws") => WebSocket.accept[JsValue, JsValue] { request =>
            flow.buffer(size = BufferSize, overflowStrategy = OverflowStrategy.backpressure)
        }
    }}

    if (StdIn.readLine(s"${java.time.Instant.now()} - Press RETURN to stop...\n") != null) {
        server.stop()
    }
}

我试图实现的行为是:

  1. 发送{“ A”:1},什么也没收到
  2. 发送{“ A”:2},什么也没收到
  3. 发送{“ A”:3},什么也没收到
  4. 发送{“ trigger”:true},收到{“ A”:3}
  5. 发送{“ trigger”:true},什么也没收到

但是我看到的是:

  1. 发送{“ A”:1},什么也没收到
  2. 发送{“ A”:2},什么也没收到
  3. 发送{“ A”:3},什么也没收到
  4. 发送{“ trigger”:true},收到{“ A”:1}
  5. 发送{“ trigger”:true},收到{“ A”:2}
  6. 发送{“ trigger”:true},收到{“ A”:3}
  7. 发送{“ trigger”:true},什么也没收到

对于zip或conflate或其他阻止接收到的JSON并以最新消息响应之前合并入站JSON的事情,我有什么误解?

1 个答案:

答案 0 :(得分:0)

conflate适用于下游比上游慢的情况。在您的情况下,上游(即标准输入正在读取的数据)比下游要慢,因此不会发生合并。

在发送数据({"A":1}{"A":2}{"A":3}时,最初不会收到任何内容,因为没有用于压缩数据的相应元素。在您发送触发消息之前,这些数据元素为buffered internally(默认缓冲区大小为16),它们用作下游发送的压缩对中的第二个元素。

要使用conflate查看所需的行为,请使下游速度慢于上游速度。在您的情况下,这有点棘手,因为您是手动输入流元素。一种想法是在流中添加throttle

val triggerBatching =
  Flow[JsValue]
    .conflate((acc, elem) => elem)
    .throttle(1, 10 seconds)

val dataBatching =
  Flow[JsValue]
    .conflate((acc, elem) => elem)
    .throttle(1, 10 seconds)

然后确保您输入输入消息的速度足够快。