我有以下scala
代码:
import akka.Done
import akka.actor.ActorSystem
import akka.kafka.ConsumerMessage.CommittableOffsetBatch
import akka.kafka.scaladsl.Consumer
import akka.kafka.{ConsumerSettings, Subscriptions}
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Sink
import org.apache.kafka.clients.consumer.{ConsumerConfig, ConsumerRecord}
import org.apache.kafka.common.serialization.StringDeserializer
import scala.concurrent.Future
object TestConsumer {
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("KafkaConsumer")
implicit val materializer = ActorMaterializer()
val consumerSettings = ConsumerSettings(system, new StringDeserializer, new StringDeserializer)
.withBootstrapServers("localhost:9092")
.withGroupId("group1")
.withProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest")
val result = Consumer
.committableSource(consumerSettings, Subscriptions.topics("test"))
.mapAsync(2)(rec => Future.successful(rec.record.value()))
.runWith(Sink.foreach(ele => {
print(ele)
system.terminate()
}))
}
}
正如您所知,应用程序会消耗来自shell上打印的kafka
的消息。
runWith
不纯,会产生一些副作用,打印出收到的消息并关闭actor。
问题是,如何使用cats IO effects使其变得纯净?有可能吗?
答案 0 :(得分:1)
你不需要猫IO
来使它变得纯净。请注意,您的sink
已经是纯粹的,因为它只是描述使用时会发生什么的价值(在这种情况下,使用意味着"连接到Source
并运行流")。
val sink: Sink[String, Future[Done]] = Sink.foreach(ele => {
print(ele)
// system.terminate() // PROBLEM: terminating the system before stream completes!
})
您描述的问题与纯度无关。问题是上面的sink
会关闭system
的值,然后在处理源的每个元素时尝试terminate
。
终止system
意味着您正在销毁用于运行流的整个运行时环境(由ActorMaterializer
使用)。这应该只在您的流完成时完成。
val result: Future[Done] = Consumer
.committableSource(consumerSettings, Subscriptions.topics("test"))
.mapAsync(2)(rec => Future.successful(rec.record.value()))
.runWith(sink)
result.onComplete(_ => system.terminate())