我想用Akka HTTP构建一个REST服务,连接到现有的Sink(使用Kafka反应流),但我无法弄清楚如何将HTTP流链接到Akka流接收器......
我应该选择使用Flows的低级Akka HTTP API吗?
我的要求是:
这是我的代码当前代码
// flow to split group of lines into lines
val splitLines = Flow[String].mapConcat(_.split("\n").toList)
// sink to produce kafka records in kafka
val kafkaSink = Flow[String]
.map(new ProducerRecord[Array[Byte], String](topic, _))
.toMat(Producer.plainSink(ProducerSettings(system,new ByteArraySerializer, new StringSerializer)))(Keep.right)
val routes = {
path("ingest") {
post {
logger.info("starting ingestion")
entity(as[GenericEvent]) { eventIngest =>
????
}~
entity(as[GenericEventList]) { eventIngestList =>
????
}
}
}
}
Http(actorSystem).bindAndHandle(routes, config.httpInterface, config.httpPort)
答案 0 :(得分:2)
有几种方法可以解决这个问题。一个建议可能是将数据直接从您的请求实体流式传输到您的kafka接收器。 extractDataBytes
指令可帮助您完成该操作(更多信息here)。
尝试以下示例中的内容。我添加了一个???
流,以允许您的特定于案例的转换正确地拆分/转换您的请求实体字节。您可以使用Framing.delimiter
之类的内容来拆分实体字节流(更多信息here)。
(extractDataBytes & extractMaterializer) { (byteSrc, mat) =>
val f = byteSrc.via(???).runWith(kafkaSink)(mat)
onComplete(f){
case Success(value) => complete(s"OK")
case Failure(ex) => complete((StatusCodes.InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
}
或者,如果要将实体解组为某个域对象,可以执行类似
的操作 (entity(as[Event]) & extractMaterializer) { (event, mat) =>
val f = Source.single(event).via(???).runWith(kafkaSink)(mat)
onComplete(f){
case Success(value) => complete(s"OK")
case Failure(ex) => complete((StatusCodes.InternalServerError, s"An error occurred: ${ex.getMessage}"))
}
}
要回答你的最后一个问题,如果Kafka背压,你的流将永远不会完成。您应该期望服务器在配置的请求超时后返回500(引用下面的文档):
默认请求超时全局应用于所有路由,可以是 使用akka.http.server.request-timeout设置进行配置(其中 默认为20秒)。