package core.framework.impl.kafka;
import core.framework.api.util.Maps;
import core.framework.api.util.StopWatch;
import core.framework.impl.log.LogManager;
import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.ByteArrayDeserializer;
import org.apache.kafka.common.serialization.ByteArraySerializer;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.util.Map;
import java.util.Set;
/**
* @author neo
*/
public class Kafka {
public final ProducerMetrics producerMetrics;
public final ConsumerMetrics consumerMetrics;
private final Logger logger = LoggerFactory.getLogger(Kafka.class);
private final String name;
private final LogManager logManager;
public String uri;
public MessageValidator validator = new MessageValidator();
public Duration maxProcessTime = Duration.ofMinutes(30);
public int maxPollRecords = 500; // default kafka setting, refer to org.apache.kafka.clients.consumer.ConsumerConfig.MAX_POLL_RECORDS_CONFIG
public int maxPollBytes = 3 * 1024 * 1024; // get 3M bytes message at max
public int minPollBytes = 1; // default kafka setting
public Duration minPollMaxWaitTime = Duration.ofMillis(500);
private Producer<String, byte[]> producer;
private KafkaMessageListener listener;
public Kafka(String name, LogManager logManager) {
this.name = name;
this.logManager = logManager;
this.producerMetrics = new ProducerMetrics(name);
this.consumerMetrics = new ConsumerMetrics(name);
}
public Producer<String, byte[]> producer() {
if (producer == null) {
producer = createProducer();
}
return producer;
}
protected Producer<String, byte[]> createProducer() {
if (uri == null) throw new Error("uri must not be null");
StopWatch watch = new StopWatch();
try {
Map<String, Object> config = Maps.newHashMap();
config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, uri);
config.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, Duration.ofSeconds(30).toMillis()); // metadata update timeout
Producer<String, byte[]> producer = new KafkaProducer<>(config, new StringSerializer(), new ByteArraySerializer());
producerMetrics.setMetrics(producer.metrics());
return producer;
} finally {
logger.info("create kafka producer, uri={}, name={}, elapsedTime={}", uri, name, watch.elapsedTime());
}
}
public Consumer<String, byte[]> consumer(String group, Set<String> topics) {
if (uri == null) throw new Error("uri must not be null");
StopWatch watch = new StopWatch();
try {
Map<String, Object> config = Maps.newHashMap();
config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, uri);
config.put(ConsumerConfig.GROUP_ID_CONFIG, group);
config.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
config.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
config.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, (int) maxProcessTime.toMillis());
config.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, (int) maxProcessTime.plusSeconds(5).toMillis());
config.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, maxPollRecords);
config.put(ConsumerConfig.FETCH_MAX_BYTES_CONFIG, maxPollBytes);
config.put(ConsumerConfig.FETCH_MIN_BYTES_CONFIG, minPollBytes);
config.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, (int) minPollMaxWaitTime.toMillis());
Consumer<String, byte[]> consumer = new KafkaConsumer<>(config, new StringDeserializer(), new ByteArrayDeserializer());
consumer.subscribe(topics);
consumerMetrics.addMetrics(consumer.metrics());
return consumer;
} finally {
logger.info("create kafka consumer, uri={}, name={}, topics={}, elapsedTime={}", uri, name, topics, watch.elapsedTime());
}
}
public KafkaMessageListener listener() {
if (listener == null) {
listener = new KafkaMessageListener(this, name, logManager);
}
return listener;
}
public void initialize() {
if (listener != null) listener.start();
}
public void close() {
if (listener != null) listener.stop();
if (producer != null) {
logger.info("close kafka producer, name={}, uri={}", name, uri);
producer.flush();
producer.close();
}
}
}