我目前正在玩akka流,并尝试了以下示例。
在请求某个HTTP端点时从kafka获取第一个元素。 这是我编写的代码及其工作原理。
get {
path("ticket" / IntNumber) { ticketNr =>
val future = Consumer.plainSource(consumerSettings, Subscriptions.topics("tickets"))
.take(1)
.completionTimeout(5 seconds)
.runWith(Sink.head)
onComplete(future) {
case Success(record) => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, record.value()))
case _ => complete(HttpResponse(StatusCodes.NotFound))
}
}
}
我只是想知道这是否是使用(akka)流的思想方式。 那么还有更多"直接"将kafka流连接到HTTP响应流的方法?
例如,POSTing时我这样做:
val kafkaTicketsSink = Flow[String]
.map(new ProducerRecord[Array[Byte], String]("tickets", _))
.toMat(Producer.plainSink(producerSettings))(Keep.right)
post {
path("ticket") {
(entity(as[Ticket]) & extractMaterializer) { (ticket, mat) => {
val f = Source.single(ticket).map(t => t.description).runWith(kafkaTicketsSink)(mat)
onComplete(f) { _ =>
val locationHeader = headers.Location(s"/ticket/${ticket.id}")
complete(HttpResponse(StatusCodes.Created, headers = List(locationHeader)))
}
}
}
}
}
也许这也可以改进??
答案 0 :(得分:2)
您可以使用Sink.queue
保留单个背压流。每次收到请求时,您都可以从物化队列中提取元素。如果可用,这应该给你一个元素,否则给你背压。
有些事情:
val queue = Consumer.plainSource(consumerSettings, Subscriptions.topics("tickets"))
.runWith(Sink.queue())
get {
path("ticket" / IntNumber) { ticketNr =>
val future: Future[Option[ConsumerRecord[String, String]]] = queue.pull()
onComplete(future) {
case Success(Some(record)) => complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, record.value()))
case _ => complete(HttpResponse(StatusCodes.NotFound))
}
}
}
Sink.queue
的更多信息可以在docs找到。