package com.neverwinterdp.kafka.tool;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParametersDelegate;
/**
* The goal of the tool is to test the stability of kafka with random network, broker, disk failure.
* The tool should:
* 1. Create a number of writer equals to the number of partition, write a message with the write period. The writer
* should stop when either max-message-per-partition or max-duration reach first.
* 2. Create a number of the partitioner reader equals to the number of partition, consume the message and verify that
* the number of message equals to the number of sent message in writer
* 3. Exit the tool, when either the readers consume all the messages or the exit-wait-time expires. The exit-wait-time
* start when all the writers terminate.
* @author Tuan
*/
public class KafkaTopicCheckTool implements Runnable {
@ParametersDelegate
private KafkaTopicConfig kafkaTopicConfig = new KafkaTopicConfig();
private KafkaMessageSendTool sendTool;
private KafkaMessageCheckTool checkTool;
private KafkaTopicReport topicReport;
private Thread deamonThread;
private boolean running = false;
public KafkaTopicCheckTool(String[] args, boolean showUsage) throws Exception {
JCommander jcommander = new JCommander(this, args);
if(showUsage) jcommander.usage();
sendTool = new KafkaMessageSendTool(kafkaTopicConfig);
checkTool = new KafkaMessageCheckTool(kafkaTopicConfig);
}
public KafkaTopicCheckTool(KafkaTopicConfig config) {
kafkaTopicConfig = config;
sendTool = new KafkaMessageSendTool(kafkaTopicConfig);
checkTool = new KafkaMessageCheckTool(kafkaTopicConfig);
}
public KafkaTopicConfig getKafkaConfig() { return this.kafkaTopicConfig ; }
public KafkaTopicReport getKafkaTopicReport() { return topicReport; }
public KafkaMessageSendTool getKafkaMessageSendTool() { return this.sendTool; }
public KafkaMessageCheckTool getKafkaMessageCheckTool() { return this.checkTool ; }
public void junitReport() throws Exception {
if(kafkaTopicConfig.junitReportFile != null && ! kafkaTopicConfig.junitReportFile.isEmpty()) {
topicReport.junitReport(kafkaTopicConfig.junitReportFile);
}
}
synchronized public boolean waitForTermination() throws InterruptedException {
if (!running) return !running;
checkTool.waitForTermination();
Thread.sleep(500);
return !running;
}
synchronized void notifyTermination() {
notifyAll();
}
public void runAsDeamon() {
if (deamonThread != null && deamonThread.isAlive()) {
throw new RuntimeException("Deamon thread is already started");
}
deamonThread = new Thread(this);
deamonThread.start();
}
public void run() {
running = true;
try {
doRun();
} catch (Exception e) {
e.printStackTrace();
}
running = false ;
}
private void doRun() throws Exception {
sendTool.runAsDeamon();
//Make sure that messgages are sending before start the failure simulator
while(!sendTool.isSending()) {
Thread.sleep(100);
}
Thread.sleep(500);
checkTool.runAsDeamon();
Thread progressReporter = new Thread() {
public void run() {
try {
while(true) {
Thread.sleep(10000);
System.out.println("Progress: sent = " + sendTool.getSentCount() + ", consumed = " + checkTool.getMessageCounter().getTotal());
}
} catch (InterruptedException e) {
System.out.println("Exit the progress reporter");
}
}
};
progressReporter.start();
sendTool.waitForTermination();
if(!checkTool.waitForTermination()) {
checkTool.setInterrupt(true);
Thread.sleep(3000);
}
progressReporter.interrupt();
topicReport = new KafkaTopicReport();
topicReport.setTopic(kafkaTopicConfig.topic);
topicReport.setNumOfPartitions(kafkaTopicConfig.numberOfPartition);
topicReport.setNumOfReplicas(kafkaTopicConfig.replication);
sendTool.populate(topicReport);
checkTool.populate(topicReport);
}
static public void main(String[] args) throws Exception {
KafkaTopicCheckTool topicCheckTool = new KafkaTopicCheckTool(args, true);
topicCheckTool.run();
//TODO: make sure this call works
topicCheckTool.junitReport();
topicCheckTool.getKafkaTopicReport().report(System.out);
topicCheckTool.getKafkaMessageCheckTool().getMessageTracker().dump(System.out);
}
}