合并和广播,构建(简单)Akka图

时间:2017-07-03 21:11:58

标签: scala akka

Akka文档很多,有很多教程。但要么它们已经过时,要么它们只涵盖基础知识(或者,我可能根本找不到合适的基础)。

我想要创建的是一个websocket应用程序,它在服务器端具有多个客户端和多个源。由于我不想从头开始,我想做出一些步骤,逐步增加我正在构建的软件的复杂性。

在完成了一些简单的流程后,我想先从一个更复杂的图开始。

我想要的是:

两个来源,一个将“keepAlive”消息从服务器推送到客户端(目前只有一个),另一个推送实际推送有用数据的消息。

现在第一个我有这个:

val tickingSource: Source[Array[Byte], Cancellable] =
  Source.tick(initialDelay = 1 second, interval = 10 seconds, tick = NotUsed)
        .zipWithIndex
        .map{ case (_, counter) => SomeMessage().toByteArray}

其中SomeMessage是protobuf类型。

因为我找不到将actor添加为源的最新方法,所以我尝试了以下第二个来源:

val secondSource = Source(1 to 1000)
val secondSourceConverter = Flow[Int].map(x => BigInteger.valueOf(x).toByteArray)

我对图表的尝试:

val g: RunnableGraph[NotUsed] = RunnableGraph.fromGraph(GraphDSL.create()
{
  implicit builder =>
  import GraphDSL.Implicits._

  val sourceMerge = builder.add(Merge[Array[Byte]](2).named("sourceMerge"))

  val x = Source(1 to 1000)

  val y = Flow[Int].map(x => BigInteger.valueOf(x).toByteArray)

  val out = Sink.ignore
  tickingSource ~> sourceMerge ~> out
  x ~> y ~> sourceMerge

  ClosedShape
})

现在g的类型为RunnableGraph[NotUsed],而我的websocket应为RunnableGraph[Array[Byte]]。我想知道:我已经做了一些完全错误的事情吗?

3 个答案:

答案 0 :(得分:1)

您需要将secondSourceConverter传递给GraphDSL.create,例如以下来自docs的示例。在这里他们导入2个接收器,但它是相同的技术。

RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((_, _)) { implicit builder =>
  (topHS, bottomHS) =>
  import GraphDSL.Implicits._
  val broadcast = builder.add(Broadcast[Int](2))
  Source.single(1) ~> broadcast.in

  broadcast.out(0) ~> sharedDoubler ~> topHS.in
  broadcast.out(1) ~> sharedDoubler ~> bottomHS.in
  ClosedShape
})

答案 1 :(得分:1)

您的图表属于RunnableGraph[NotUsed],因为您使用的是Sink.ignore。您可能想要RunnableGraph[Future[Array[Byte]]]而不是RunnableGraph[Array[Byte]]

val byteSink = Sink.fold[Array[Byte], Array[Byte]](Array[Byte]())(_ ++ _)

val g = RunnableGraph.fromGraph(GraphDSL.create(byteSink) { implicit builder => bSink =>
  import GraphDSL.Implicits._

  val sourceMerge = builder.add(Merge[Array[Byte]](2))
  tickingSource ~> sourceMerge ~> bSink.in
  secondSource ~> secondSourceConverter ~> sourceMerge

  ClosedShape
})
// RunnableGraph[Future[Array[Byte]]]

答案 2 :(得分:0)

我不确定您希望如何处理传入的消息,但这是一个简单的示例。希望它能帮到你。

path("ws") {
   extractUpgradeToWebSocket { upgrade =>
    complete {
      import scala.concurrent.duration._
      val tickSource = Source.tick(1.second, 1.second, TextMessage("ping"))
      val messagesSource = Source.queue(10, OverflowStrategy.backpressure)
      messagesSource.mapMaterializedValue { queue =>
        //do something with out queue
        //like myHandler ! RegisterOutQueue(queue)
      }
      val sink = Sink.ignore
      val source = tickSource.merge(messagesSource)
      upgrade.handleMessagesWithSinkSource(
        inSink = sink,
        outSource = source
      )
   }
}