我正在尝试为Flink流作业创建一个JUnit测试,该作业将数据写入kafka主题并分别使用FlinkKafkaProducer09
和FlinkKafkaConsumer09
从同一kafka主题读取数据。我正在传递产品中的测试数据:
DataStream<String> stream = env.fromElements("tom", "jerry", "bill");
并检查相同数据是否来自消费者:
List<String> expected = Arrays.asList("tom", "jerry", "bill");
List<String> result = resultSink.getResult();
assertEquals(expected, result);
使用TestListResultSink
。
我可以通过打印流来查看来自消费者的数据。但无法获得Junit测试结果,因为消费者即使在消息完成后也会继续运行。所以它没有来测试部分。
在Flink
或FlinkKafkaConsumer09
中是否可以以任何方式停止流程或运行特定时间?
答案 0 :(得分:5)
潜在的问题是流媒体程序通常不是有限的并且无限期地运行。
至少在目前,最好的方法是在流中插入一条特殊的控制消息,让源正确终止(只需通过离开读取循环停止读取更多数据)。这样Flink就会告诉所有下游运营商,他们可以在消耗完所有数据后停止运营。
或者,您可以在源中引发特殊异常(例如,在一段时间之后),以便您可以区分“正确”终止与故障情况(通过检查错误原因)。在源代码中抛出异常将使程序失败。
答案 1 :(得分:0)
关注@TillRohrman
如果使用EmbeddedKafka实例,可以组合特殊异常方法并在单元测试中处理它,然后读取EmbeddedKafka主题并断言消费者值。
我发现https://github.com/asmaier/mini-kafka/blob/master/src/test/java/de/am/KafkaProducerIT.java在这方面非常有用。
唯一的问题是您将丢失触发异常的元素,但您始终可以调整测试数据以解决此问题。
答案 2 :(得分:0)
您是否可以在反序列化器中使用isEndOfStream覆盖来停止从Kafka获取?如果我读得正确,flink / Kafka09Fetcher在其run方法中有以下代码,它会破坏事件循环
if (deserializer.isEndOfStream(value)) {
// end of stream signaled
running = false;
break;
}
我的想法是使用Till Rohrmann关于控制消息的想法与这个isEndOfStream方法一起告诉KafkaConsumer停止阅读。
任何不起作用的理由?或者也许是我忽略的一些角落?
答案 3 :(得分:0)
在测试中,您可以在单独的线程中开始执行作业,等待一段时间以允许它进行数据处理,取消线程(它将中断作业)并进行攻击。
CompletableFuture<Void> handle = CompletableFuture.runAsync(() -> {
try {
environment.execute(jobName);
} catch (Exception e) {
e.printStackTrace();
}
});
try {
handle.get(seconds, TimeUnit.SECONDS);
} catch (TimeoutException e) {
handle.cancel(true); // this will interrupt the job execution thread, cancel and close the job
}
// Make assertions here