Akka Http中的Web Socket连接被视为Akka Streams Flow
。这似乎对于基本的请求 - 回复非常有用,但是当消息也应该通过websocket推出时,它会变得更加复杂。我服务器的核心看起来像:
lazy val authSuccessMessage = Source.fromFuture(someApiCall)
lazy val messageFlow = requestResponseFlow
.merge(updateBroadcastEventSource)
lazy val handler = codec
.atop(authGate(authSuccessMessage))
.join(messageFlow)
handleWebSocketMessages {
handler
}
此处,codec
是(de)序列化BidiFlow
,authGate
是BidiFlow
,它处理授权消息并防止任何消息流出,直到授权成功。成功后,它会发送authSuccessMessage
作为回复。 requestResponseFlow
是标准的请求 - 回复模式,updateBroadcastEventSource
混合了异步推送消息。
我希望能够在某些情况下发送错误消息并正常终止连接,例如错误授权,someApiCall
失败或requestResponseFlow
处理的错误请求。所以基本上,基本上我似乎希望能够用最后一条消息异步完成messageFlow
,即使它的其他成分流仍然存在。
答案 0 :(得分:0)
使用KillSwitch
了解如何执行此操作。
更新版本
旧版本存在的问题是,当堆叠中的BidiFlow
阶段(例如我的authGate
)触发时,它似乎无法工作。我不确定为什么,但将关闭建模为BidiFlow
本身,放在堆栈的更上方,解决了这个问题。
val shutoffPromise = Promise[Option[OutgoingWebsocketEvent]]()
/**
* Shutoff valve for the connection. It is triggered when `shutoffPromise`
* completes, and sends a final optional termination message if that
* promise resolves with one.
*/
val shutoffBidi = {
val terminationMessageSource = Source
.maybe[OutgoingWebsocketEvent]
.mapMaterializedValue(_.completeWith(shutoffPromise.future))
val terminationMessageBidi = BidiFlow.fromFlows(
Flow[IncomingWebsocketEventOrAuthorize],
Flow[OutgoingWebsocketEvent].merge(terminationMessageSource)
)
val terminator = BidiFlow
.fromGraph(KillSwitches.singleBidi[IncomingWebsocketEventOrAuthorize, OutgoingWebsocketEvent])
.mapMaterializedValue { killSwitch =>
shutoffPromise.future.foreach { _ => println("Shutting down connection"); killSwitch.shutdown() }
}
terminationMessageBidi.atop(terminator)
}
然后我将其应用于codec
:
val handler = codec
.atop(shutoffBidi)
.atop(authGate(authSuccessMessage))
.join(messageFlow)
旧版
val shutoffPromise = Promise[Option[OutgoingWebsocketEvent]]()
/**
* Shutoff valve for the flow of outgoing messages. It is triggered when
* `shutoffPromise` completes, and sends a final optional termination
* message if that promise resolves with one.
*/
val shutoffFlow = {
val terminationMessageSource = Source
.maybe[OutgoingWebsocketEvent]
.mapMaterializedValue(_.completeWith(shutoffPromise.future))
Flow
.fromGraph(KillSwitches.single[OutgoingWebsocketEvent])
.mapMaterializedValue { killSwitch =>
shutoffPromise.future.foreach(_ => killSwitch.shutdown())
}
.merge(terminationMessageSource)
}
然后handler
看起来像:
val handler = codec
.atop(authGate(authSuccessMessage))
.join(messageFlow via shutoffFlow)