gpt4 book ai didi

java - EmbeddedKafka在后续测试中延迟后向消费者发送消息

转载 作者:行者123 更新时间:2023-12-02 02:29:47 25 4
gpt4 key购买 nike

我正在使用 kafka-spring-test 的 EmbeddedKafka,版本 2.0.1.RELEASE(最新)。我有非常简单的测试,在仅运行一项测试时可以正常工作。 但是每当我一个接一个地运行它们时(因此只需运行整个测试类),第二个就会失败 - 消费者不会收到任何消息。

public class KafkaControllerTest {

private static final String FOO_TOPIC = "fooTopic";

@Rule
public KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, FOO_TOPIC);

MessageConsumer msgConsumerFoo = mock(MessageConsumer.class);

@Before
public void before() {
assertTrue(embeddedKafka.getBrokerAddresses().length == 1);
KafkaController controller = new KafkaController(
embeddedKafka.getBrokerAddress(0).toString(),
new Consumer(FOO_TOPIC, msgConsumerFoo));
MockMvcBuilders.standaloneSetup(controller).build();
}

@Test
public void kafkaFirstTest() throws Exception {
sendMessage(FOO_TOPIC, "foo message");

verify(msgConsumerFoo).consume(any());
}

@Test
public void kafkaSecondTest() throws Exception {
sendMessage(FOO_TOPIC, "foo2 message");

verify(msgConsumerFoo).consume(any());
}

void sendMessage(String topic, String notification) throws ExecutionException, InterruptedException {
Map<String, Object> props = KafkaTestUtils.producerProps(embeddedKafka);
Producer<Integer, String> producer = new DefaultKafkaProducerFactory<Integer, String>(props).createProducer();
producer.send(new ProducerRecord<>(topic, notification)).get();
}
}

测试类的代码:

public class KafkaController {

public KafkaController(String brokerAddress, Consumer... consumers) {
for (Consumer consumer : consumers) {
addTopicListener(brokerAddress, consumer.topic, consumer.messageConsumer);
}
}

private void addTopicListener(String brokerAddress, String topic, MessageConsumer consumer) {
HashMap<String, Object> consumerConfig = new HashMap<>();
consumerConfig.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerAddress);
consumerConfig.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString());
DefaultKafkaConsumerFactory<String, String> cf = new DefaultKafkaConsumerFactory<>(
consumerConfig,
new StringDeserializer(),
new StringDeserializer());

ContainerProperties containerProperties = new ContainerProperties(topic);
containerProperties.setMessageListener((MessageListener<String, String>) data -> {
consumer.consume(data.value());
});
ConcurrentMessageListenerContainer container = new ConcurrentMessageListenerContainer<>(cf, containerProperties);
container.start();
}

public interface MessageConsumer {
void consume(String message);
}

public static class Consumer {
private final String topic;
private final MessageConsumer messageConsumer;

public Consumer(String topic, MessageConsumer messageConsumer) {
this.topic = topic;
this.messageConsumer = messageConsumer;
}
}
}

我认为该问题是由 KafkaEmbedded 引起的,因为使用本地 Kafka 实例测试的消费者工作正常。

我有什么遗漏的吗?我没有找到任何可能有帮助的消费者属性(property)。

Kafka-spring-test doc说:

It is generally recommended to use the rule as a @ClassRule to avoid starting/stopping the broker between tests (and use a different topic for each test).

但是,我尝试将 KafkaEmbedded 制作为 @ClassRule 并在测试中使用不同的主题,但仍然一无所获。

这个问题与异步性有关,因为在第二次测试中添加延迟会有所帮助:

@Test
public void kafkaSecondTest() throws Exception {
Thread.sleep(1000);
sendMessage(FOO_TOPIC, "foo2 message");
Thread.sleep(1000);

verify(msgConsumerFoo).consume(any());
}

是的,不知何故,只有在发送消息之前和之后添加 Thread.sleep(1000) 时它才有效。

那么我如何检查KafkaEmbedded或其他组件是否准备好发送/使用消息?

最佳答案

您可能需要设置auto.offset.reset=earliest (ConsumerConfig.AUTO_OFFSET_RESET_CONFIG)。否则,您可能会在容器完全启动之前发送消息。

当然,如果使用相同的主题,第二个消费者应该收到 2 条消息。

此外,我建议在每次测试结束时停止容器。调试日志记录也应该有所帮助。

编辑

另一种方法是在测试中发送消息之前使用ContainerTestUtils.waitForAssignment();我们在框架测试中经常这样做。

关于java - EmbeddedKafka在后续测试中延迟后向消费者发送消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47312373/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com