Kafkaトピックにメッセージを送信するSpringBootアプリケーションを作成しました。Springspring-integration-kafka
を使用しています:KafkaProducerMessageHandler<String,String>
はチャネル(SubscribableChannel
)にサブスクライブされ、すべてをプッシュします1つのトピックに対して受信したメッセージ。アプリケーションは正常に動作します。コンソールコンシューマー(ローカルkafka)経由でKafkaにメッセージが到着します。
また、KafkaEmbedded
を使用するIntegrationtestを作成します。テスト内のチャネルにサブスクライブすることで、予期されるメッセージを確認しています-すべて問題ありません。
しかし、私はテストでkafkaに入れられたメッセージもチェックしたいと思います。悲しいことに、KafkaのJavaDocは最高ではありません。私がこれまでに試したことは:
@ClassRule
public static KafkaEmbedded kafkaEmbedded = new KafkaEmbedded(1, true, "myTopic");
//...
@Before
public void init() throws Exception {
mockConsumer = new MockConsumer<>( OffsetResetStrategy.EARLIEST );
kafkaEmbedded.consumeFromAnEmbeddedTopic( mockConsumer,"sikom" );
}
//...
@Test
public void endToEnd() throws Exception {
// ...
ConsumerRecords<String, String> records = mockConsumer.poll( 10000 );
StreamSupport.stream(records.spliterator(), false).forEach( record -> log.debug( "record: " + record.value() ) );
}
問題は、レコードが表示されないことです。 KafkaEmbeddedの設定が正しいかどうかわかりません。ただし、メッセージはチャネルによって受信されます。
これは私のために働きます。試してみる
_@RunWith(SpringRunner.class)
@SpringBootTest
public class KafkaEmbeddedTest {
private static String SENDER_TOPIC = "testTopic";
@ClassRule
// By default it creates two partitions.
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SENDER_TOPIC);
@Test
public void testSend() throws InterruptedException, ExecutionException {
Map<String, Object> senderProps = KafkaTestUtils.producerProps(embeddedKafka);
//If you wish to send it to partitions other than 0 and 1,
//then you need to specify number of paritions in the declaration
KafkaProducer<Integer, String> producer = new KafkaProducer<>(senderProps);
producer.send(new ProducerRecord<>(SENDER_TOPIC, 0, 0, "message00")).get();
producer.send(new ProducerRecord<>(SENDER_TOPIC, 0, 1, "message01")).get();
producer.send(new ProducerRecord<>(SENDER_TOPIC, 1, 0, "message10")).get();
Map<String, Object> consumerProps = KafkaTestUtils.consumerProps("sampleRawConsumer", "false", embeddedKafka);
// Make sure you set the offset as earliest, because by the
// time consumer starts, producer might have sent all messages
consumerProps.put("auto.offset.reset", "earliest");
final List<String> receivedMessages = Lists.newArrayList();
final CountDownLatch latch = new CountDownLatch(3);
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
KafkaConsumer<Integer, String> kafkaConsumer = new KafkaConsumer<>(consumerProps);
kafkaConsumer.subscribe(Collections.singletonList(SENDER_TOPIC));
try {
while (true) {
ConsumerRecords<Integer, String> records = kafkaConsumer.poll(100);
records.iterator().forEachRemaining(record -> {
receivedMessages.add(record.value());
latch.countDown();
});
}
} finally {
kafkaConsumer.close();
}
});
latch.await(10, TimeUnit.SECONDS);
assertTrue(receivedMessages.containsAll(Arrays.asList("message00", "message01", "message10")));
}
}
_
Producer.Send(..)
は非同期操作であるため、カウントダウンラッチを使用しています。したがって、ここで行っているのは、無限ループでのポーリングkafka 100ミリ秒ごと、新しいレコードがある場合は、将来のアサーションのためにリストに追加して、カウントダウンを減らすことです。念のため、合計10秒待ちます。
単純なループを使用して、数分後に終了することもできます(CountdownLatchやExecutorServiceのものを使用したくない場合)