web-dev-qa-db-ja.com

kafka埋め込み:Java.io.FileNotFoundException:/tmp/kafka-7785736914220873149/replication-offset-checkpoint.tmp

統合テストでkafkaEmbeddedを使用すると、FileNotFoundExceptionが発生します。

Java.io.FileNotFoundException: /tmp/kafka-7785736914220873149/replication-offset-checkpoint.tmp 
at Java.io.FileOutputStream.open0(Native Method) ~[na:1.8.0_141]
at Java.io.FileOutputStream.open(FileOutputStream.Java:270) ~[na:1.8.0_141]
at Java.io.FileOutputStream.<init>(FileOutputStream.Java:213) ~[na:1.8.0_141]
at Java.io.FileOutputStream.<init>(FileOutputStream.Java:162) ~[na:1.8.0_141]
at kafka.server.checkpoints.CheckpointFile.write(CheckpointFile.scala:43) ~[kafka_2.11-0.11.0.0.jar:na]
at kafka.server.checkpoints.OffsetCheckpointFile.write(OffsetCheckpointFile.scala:58) ~[kafka_2.11-0.11.0.0.jar:na]
at kafka.server.ReplicaManager$$anonfun$checkpointHighWatermarks$2.apply(ReplicaManager.scala:1118) [kafka_2.11-0.11.0.0.jar:na]
at kafka.server.ReplicaManager$$anonfun$checkpointHighWatermarks$2.apply(ReplicaManager.scala:1115) [kafka_2.11-0.11.0.0.jar:na]
at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:733) [scala-library-2.11.11.jar:na]
at scala.collection.immutable.Map$Map1.foreach(Map.scala:116) [scala-library-2.11.11.jar:na]
at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:732) [scala-library-2.11.11.jar:na]
at kafka.server.ReplicaManager.checkpointHighWatermarks(ReplicaManager.scala:1115) [kafka_2.11-0.11.0.0.jar:na]
at kafka.server.ReplicaManager$$anonfun$1.apply$mcV$sp(ReplicaManager.scala:211) [kafka_2.11-0.11.0.0.jar:na]
at kafka.utils.KafkaScheduler$$anonfun$1.apply$mcV$sp(KafkaScheduler.scala:110) [kafka_2.11-0.11.0.0.jar:na]
at kafka.utils.CoreUtils$$anon$1.run(CoreUtils.scala:57) [kafka_2.11-0.11.0.0.jar:na]
at Java.util.concurrent.Executors$RunnableAdapter.call(Executors.Java:511) [na:1.8.0_141]
at Java.util.concurrent.FutureTask.runAndReset(FutureTask.Java:308) [na:1.8.0_141]
at Java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.Java:180) [na:1.8.0_141]
at Java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.Java:294) [na:1.8.0_141]
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149) [na:1.8.0_141]
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624) [na:1.8.0_141]
at Java.lang.Thread.run(Thread.Java:748) [na:1.8.0_141]

テストは成功しましたが、ビルドの最後にこのエラーが発生します

何時間もの研究の後、私はこれを発見しました:

  • kafka TestUtils.tempDirectoryメソッドは、埋め込まれたkafkaブローカーの一時ディレクトリを作成するために使用されます。また、JVMの終了時にこのディレクトリを削除するシャットダウンフックを登録します。
  • 単体テストの実行が完了すると、System.exitが呼び出され、登録されているすべてのシャットダウンフックが実行されます。

kafkaブローカーが単体テストの最後に実行される場合、ブローカーは削除されたdirにデータを読み書きしようとし、異なるFileNotFound例外を生成します。

私の設定クラス:

@Configuration
public class KafkaEmbeddedConfiguration {

private final KafkaEmbedded kafkaEmbedded;

public KafkaEmbeddedListenerConfigurationIT() throws Exception {
    kafkaEmbedded = new KafkaEmbedded(1, true, "topic1");
    kafkaEmbedded.before();
}

@Bean
public KafkaTemplate<String, Message> sender(ProtobufSerializer protobufSerializer,
        KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry) throws Exception {
    KafkaTemplate<String, Message> sender = KafkaTestUtils.newTemplate(kafkaEmbedded, new StringSerializer(),
            protobufSerializer);
for (MessageListenerContainer listenerContainer : 
registry.getListenerContainers()) {
        ContainerTestUtils.waitForAssignment(listenerContainer, 
kafkaEmbedded.getPartitionsPerTopic());
    }        

    return sender;
}

テストクラス:

@RunWith(SpringRunner.class)
public class DeviceEnergyKafkaListenerIT {
 ...
@Autowired
private KafkaTemplate<String, Message> sender;

@Test
public void test (){
    ...
    sender.send(topic, msg);
    sender.flush();
}

これを解決する方法はありますか?

10
qasmi

@ClassRuleブローカーを使用して、@AfterClassメソッドを追加します...

@AfterClass
public static void tearDown() {
    embeddedKafka.getKafkaServers().forEach(b -> b.shutdown());
    embeddedKafka.getKafkaServers().forEach(b -> b.awaitShutdown());
}

@RuleまたはBeanの場合は、@Afterメソッドを使用します。

7
Gary Russell
final KafkaServer server = 
embeddedKafka.getKafkaServers().stream().findFirst().orElse(null);  
if(server != null) {
  server.replicaManager().shutdown(false);
final Field replicaManagerField = server.getClass().getDeclaredField("replicaManager");
if(replicaManagerField != null) {
    replicaManagerField.setAccessible(true);
    replicaManagerField.set(server, null);
 }
}
embeddedKafka.after();

詳細については、このスレッドを参照してください Embedded kafka同じコンテキストを使用した複数のテストの問題

1
pannu