如何使用Akka Streams和Akka HTTP订阅websockets到actor的消息?

时间:2017-02-06 22:45:40

标签: akka akka-stream akka-http

我想通过websockets向客户发送通知。这些通知是由actor生成的,因此我试图在服务器启动时创建一个actor的消息流,并订阅websockects与此流的连接(仅发送自订阅以来发出的那些通知)

使用Source.actorRef,我们可以创建一个演员消息来源。

val ref = Source.actorRef[Weather](Int.MaxValue, fail)
                .filter(!_.raining)
                .to(Sink foreach println )
                .run()

ref ! Weather("02139", 32.0, true)

但是,如果已经实现了这个来源,我如何订阅(akka http *)websockets连接呢?

* Akka HTTP中的WebSockets连接需要Flow [Message,Message,Any]

我正在尝试做的事情就像是

// at server startup
val notifications: Source[Notification,ActorRef] = Source.actorRef[Notificacion](5,OverflowStrategy.fail)
val ref = notifications.to(Sink.foreach(println(_))).run()
val notificationActor = system.actorOf(NotificationActor.props(ref))

// on ws connection
val notificationsWS = path("notificationsWS") {
  parameter('name) { name ⇒
    get {
      onComplete(flow(name)){
        case Success(f) => handleWebSocketMessages(f)
        case Failure(e) => throw e
      }
    }
  }
}

def flow(name: String) = {
  val messages = notifications filter { n => n.name equals name } map { n => TextMessage.Strict(n.data) }
  Flow.fromSinkAndSource(Sink.ignore, notifications)
}

这种做法不起作用,因为通知源不是物化的,因此它不会发出任何元素。

注意:我使用的是Source.actorPublisher并且它正在运行但是ktoso discourages his usage并且我也收到了此错误:

java.lang.IllegalStateException: onNext is not allowed when the stream has not requested elements, totalDemand was 0.

1 个答案:

答案 0 :(得分:1)

您可以使用actorRef将具体化的mapMaterializedValue公开给某个外部路由器角色。

Flow.fromSinkAndSourceMat(Sink.ignore, notifications)(Keep.right)
  .mapMaterializedValue(srcRef => router ! srcRef)

路由器可以跟踪你的来源actorrefs(deathwatch可以帮助整理)并将消息转发给他们。

注意:您可能已经知道了,但请注意,通过使用Source.actorRef来提供您的流量,您的流量将无法识别背压(使用您选择的策略只会在负载下崩溃)。