All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finatra.kafka.consumers.FinagleKafkaConsumerBuilder.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.finatra.kafka.consumers

import com.twitter.conversions.DurationOps._
import com.twitter.finatra.kafka.config.{KafkaConfig, ToKafkaProperties}
import com.twitter.finatra.kafka.domain.SeekStrategy
import com.twitter.finatra.kafka.stats.KafkaFinagleMetricsReporter
import com.twitter.util.Duration
import java.util.Properties
import org.apache.kafka.clients.consumer.{ConsumerConfig, KafkaConsumer}
import org.apache.kafka.common.serialization.Deserializer

/**
 * Trait defining methods for configuring a FinagleKafkaConsumer.
 * It extends KafkaConsumerConfig, to get all the Kafka-specific methods that
 * set elements of the java.util.Properties object.
 * It also adds methods for configuring new parameters that are specific to
 * FinagleKafkaConsumer (pollTimeout and seekStrategy).
 *
 * @tparam K The key type of the consumer this will build.
 * @tparam V The value type of the consumer this will build.
 * @tparam Self The type of the concrete builder that includes these methods.
 */
trait FinagleKafkaConsumerBuilderMethods[K, V, Self] extends KafkaConsumerConfigMethods[Self] {

  /**
   * The KafkaConsumerConfig config, which can be used to build KafkaConsumer
   */
  def config: FinagleKafkaConsumerConfig[K, V]
  protected def fromFinagleConsumerConfig(config: FinagleKafkaConsumerConfig[K, V]): This

  override protected def configMap: Map[String, String] =
    config.kafkaConsumerConfig.configMap
  override protected def fromConfigMap(configMap: Map[String, String]): This =
    fromFinagleConsumerConfig(
      config.copy(kafkaConsumerConfig = KafkaConsumerConfig(configMap))
    )

  /**
   * Deserializer class for key
   */
  def keyDeserializer(keyDeserializer: Deserializer[K]): This =
    fromFinagleConsumerConfig(config.copy(keyDeserializer = Some(keyDeserializer)))

  /**
   * Deserializer class for value
   */
  def valueDeserializer(valueDeserializer: Deserializer[V]): This =
    fromFinagleConsumerConfig(
      config.copy(valueDeserializer = Some(valueDeserializer))
    )

  /**
   * Default poll timeout in milliseconds
   */
  def pollTimeout(pollTimeout: Duration): This =
    fromFinagleConsumerConfig(config.copy(pollTimeout = pollTimeout))

  /**
   * Whether the consumer should start from end, beginning or from the offset
   */
  def seekStrategy(seekStrategy: SeekStrategy): This =
    fromFinagleConsumerConfig(config.copy(seekStrategy = seekStrategy))

  /**
   * If using SeekStrategy.REWIND, specify the duration back in time to rewind and start consuming from
   */
  def rewindDuration(rewindDuration: Duration): This =
    fromFinagleConsumerConfig(config.copy(rewindDuration = Some(rewindDuration)))

  /**
   * For KafkaFinagleMetricsReporter: whether to include node-level metrics.
   */
  def includeNodeMetrics(include: Boolean): This =
    fromFinagleConsumerConfig(config.copy(includeNodeMetrics = include))

  /**
   * For KafkaFinagleMetricsReporter: whether to include node-level metrics.
   */
  def includePartitionMetrics(include: Boolean): This =
    fromFinagleConsumerConfig(config.copy(includePartitionMetrics = include))

  @deprecated("Use buildClient instead", "2018-05-30")
  def build(): FinagleKafkaConsumer[K, V] = {
    validateConfigs(config)
    new FinagleKafkaConsumer[K, V](config)
  }

  /**
   * Create the native KafkaConsumer client.
   */
  def buildClient(): KafkaConsumer[K, V] = {
    validateConfigs(config)
    new KafkaConsumer[K, V](
      config.properties,
      config.keyDeserializer.get,
      config.valueDeserializer.get)
  }

  protected def validateConfigs(config: FinagleKafkaConsumerConfig[K, V]): Unit = {
    require(
      configMap.get(ConsumerConfig.GROUP_ID_CONFIG).isDefined,
      "FinagleKafkaConsumerBuilder: groupId must be configured"
    )
    require(
      config.keyDeserializer.isDefined,
      "FinagleKafkaConsumerBuilder: keyDeserializer must be configured"
    )
    require(
      config.valueDeserializer.isDefined,
      "FinagleKafkaConsumerBuilder: valueDeserializer must be configured"
    )
  }
}

case class FinagleKafkaConsumerBuilder[K, V](
  override val config: FinagleKafkaConsumerConfig[K, V] = FinagleKafkaConsumerConfig[K, V]())
    extends FinagleKafkaConsumerBuilderMethods[K, V, FinagleKafkaConsumerBuilder[K, V]] {
  override protected def fromFinagleConsumerConfig(config: FinagleKafkaConsumerConfig[K, V]): This =
    new FinagleKafkaConsumerBuilder[K, V](config)
}

case class FinagleKafkaConsumerConfig[K, V](
  kafkaConsumerConfig: KafkaConsumerConfig = KafkaConsumerConfig(),
  keyDeserializer: Option[Deserializer[K]] = None,
  valueDeserializer: Option[Deserializer[V]] = None,
  pollTimeout: Duration = 100.millis,
  seekStrategy: SeekStrategy = SeekStrategy.RESUME,
  rewindDuration: Option[Duration] = None,
  includeNodeMetrics: Boolean = false,
  includePartitionMetrics: Boolean = true)
    extends KafkaConfig
    with ToKafkaProperties {
  override protected def configMap: Map[String, String] = kafkaConsumerConfig.configMap

  override def properties: Properties = {
    val properties = super.properties

    properties.put(KafkaFinagleMetricsReporter.IncludeNodeMetrics, includeNodeMetrics.toString)
    properties.put(
      KafkaFinagleMetricsReporter.IncludePartitionMetrics,
      includePartitionMetrics.toString)

    properties
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy