Http Websocket as Akka Stream Source

时间:2018-01-08 15:40:26

标签: java scala akka akka-stream akka-http

我想使用akka流来收听websocket。也就是说,我希望将其视为Source

但是,所有official examples都将websocket连接视为Flow

我目前的方法是将websocketClientFlowSource.maybe结合使用。当在流中没有新的TcpIdleTimeoutException被发送时,这最终会导致上游因Message而失败。

因此,我的问题有两个:

  1. 有没有办法 - 我明显错过了 - 将websocket视为Source
  2. 如果使用Flow是唯一选项,那么如何正确处理TcpIdleTimeoutException?通过提供流监督策略无法处理该异常。使用RestartSource重新启动源也没有帮助,因为源不是问题。
  3. 更新

    所以我尝试了两种不同的方法,为方便起见,将空闲超时设置为1秒

    application.conf

    akka.http.client.idle-timeout = 1s
    

    使用keepAlive(由Stefano建议)

    Source.<Message>maybe()
        .keepAlive(Duration.apply(1, "second"), () -> (Message) TextMessage.create("keepalive"))
        .viaMat(Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri)), Keep.right())
        { ... }
    

    执行此操作时,上游仍然会失败并显示TcpIdleTimeoutException

    使用RestartFlow

    但是,我使用RestartFlow

    了解了this approach
    final Flow<Message, Message, NotUsed> restartWebsocketFlow = RestartFlow.withBackoff(
        Duration.apply(3, TimeUnit.SECONDS),
        Duration.apply(30, TimeUnit.SECONDS),
        0.2,
        () -> createWebsocketFlow(system, websocketUri)
    );
    
    Source.<Message>maybe()
        .viaMat(restartWebsocketFlow, Keep.right()) // One can treat this part of the resulting graph as a `Source<Message, NotUsed>`
        { ... }
    
    (...)
    
    private Flow<Message, Message, CompletionStage<WebSocketUpgradeResponse>> createWebsocketFlow(final ActorSystem system, final String websocketUri) {
        return Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri));
    }
    

    这可以解决我可以将websocket视为Source(虽然人为地,如Stefano所解释的那样)并且每当websocketClientFlow发生时重新启动Exception来保持tcp连接活动。

    但这并不是最佳解决方案。

2 个答案:

答案 0 :(得分:3)

  1. 没有。 WebSocket是双向通道,因此Akka-HTTP将其建模为Flow。如果在您的特定情况下,您只关心频道的一侧,那么您可以使用FlowFlow.fromSinkAndSource(Sink.ignore, mySource)来构建一个带有“静音”一侧的Flow.fromSinkAndSource(mySink, Source.maybe),具体取决于您关于案件。

  2. 根据documentation

      

    将根据以下内容删除非活动WebSocket连接   空闲超时设置。如果您需要保持非活动连接   活着,你可以调整你的空闲超时或注入'keep-alive'   定期发送消息。

    有一个ad-hoc组合器可以注入保持活动消息,请参阅下面的示例和此Akka cookbook recipe。注意:这应该发生在客户端。

    src.keepAlive(1.second, () => TextMessage.Strict("ping"))

答案 1 :(得分:0)

我希望我能正确理解你的问题。您在寻找asSourceOf吗?

path("measurements") {
  entity(asSourceOf[Measurement]) { measurements =>
    // measurement has type Source[Measurement, NotUsed]
    ...
  }
}