在Akka流中串联流

时间:2018-10-17 22:23:00

标签: scala akka akka-stream apache-kafka-streams akka-http

我们正在使用Kafka,并希望使用interactive queries来访问状态存储中的数据。我们已有一个使用Akka HTTP来提供REST API的服务,并且我们希望将交互式查询集成到流中。

kafka-streams-query似乎是最合适的选择。但是,它通过公开使用低级API的route属性(它映射到Flow[HttpRequest, HttpResponse, Any])而集成到Akka HTTP中。我们之前的所有代码都使用Akka HTTP的路由DSL将代码连接起来。

我希望像下面这样的代码能够正常工作,但不会:

implicit val system:ActorSystem = ActorSystem("web")
implicit val materializer:ActorMaterializer = ActorMaterializer()
implicit val ec = system.dispatcher

val firstRoutes:Route = ... //a route object populated
val lastRoutes:Route = ... //other route object populad

val iqServiceFlow:Flow[HttpRequest, HttpResponse, Any] = ...// code that returns the interactive query service

val firstFlow = Route.handlerFlow(firstRoutes)
val lastFlow = Route.handlerFlow(lastRoutes)

// The following code doesn't work though everything I've seen online suggests it should
val handler = firstFlow via iqServiceFlow via lastFlow

Http().bindAndHandle(handler, "0.0.0.0", 8000)

如何在Akka流中合并流?

修改: 更正了处理程序分配语句。

1 个答案:

答案 0 :(得分:3)

为清楚起见,让我们首先明确所有返回类型:

val iqServiceFlow: Flow[HttpRequest, HttpResponse, Any] = ...
val firstFlow: Flow[HttpRequest, HttpResponse, NotUsed] = Route.handlerFlow(firstRoutes)
val lastFlow: Flow[HttpRequest, HttpResponse, NotUsed]  = Route.handlerFlow(lastRoutes)

此外,代替...

val handler = firstRoutes via iqServiceFlow via lastFlow

...您可能是说:

val handler = firstFlow via iqServiceFlow via lastFlow

为了将流与via链接在一起,输入和输出类型必须匹配:即,第一个流的输出类型必须与第二个流的输入类型相同,依此类推。您要对处理程序执行的操作如下:

[HttpRequest, HttpResponse] // firstFlow
                   |
                   v
             [HttpRequest, HttpResponse] // iqServiceFlow
                                |
                                v
                          [HttpRequest, HttpResponse] // lastFlow

所有流的输出类型为HttpResponse,但它们各自的输入类型均为HttpRequest,因此无法将它们与via链接在一起。

要链接流,您需要一个函数以某种方式将HttpResponse转换为HttpRequest

val respToReq: HttpResponse => HttpRequest = ...

您可以通过上述功能创建流程:

val convertingFlow: Flow[HttpResponse, HttpRequest] = Flow.fromFunction(respToReq)

现在您可以链接流程了:

val handler = firstFlow via convertingFlow via iqServiceFlow via convertingFlow via lastFlow

类型对齐如下:

[HttpRequest, HttpResponse] // firstFlow
                   |
                   v
             [HttpResponse, HttpRequest] // convertingFlow
                                |
                                v
                           [HttpRequest, HttpResponse] // iqServiceFlow
                                              |
                                              v
                                        [HttpResponse, HttpRequest] // convertingFlow
                                                            |
                                                            v                              
                                                      [HttpRequest, HttpResponse] // lastFlow

以上假设您可以重复使用相同的转换函数/流。如果这种假设不成立,您显然可以创建不同的转换函数/流。