Browse Source
feat: Add standalone Java SeekToBeginning test to reproduce the issue
feat: Add standalone Java SeekToBeginning test to reproduce the issue
Created: - SeekToBeginningTest.java: Standalone Java test that reproduces the seekToBeginning() hang - Dockerfile.seektest: Docker setup for running the test - pom.xml: Maven build configuration - Updated docker-compose.yml to include seek-test service This test simulates what Schema Registry does: 1. Create KafkaConsumer connected to gateway 2. Assign to _schemas topic partition 0 3. Call seekToBeginning() 4. Poll for records Expected behavior: Should send ListOffsets and then Fetch Actual behavior: Blocks indefinitely after seekToBeginning()pull/7329/head
4 changed files with 171 additions and 0 deletions
-
20test/kafka/kafka-client-loadtest/Dockerfile.seektest
-
73test/kafka/kafka-client-loadtest/SeekToBeginningTest.java
-
18test/kafka/kafka-client-loadtest/docker-compose.yml
-
60test/kafka/kafka-client-loadtest/pom.xml
@ -0,0 +1,20 @@ |
|||||
|
FROM openjdk:11-jdk-slim |
||||
|
|
||||
|
# Install Maven |
||||
|
RUN apt-get update && apt-get install -y maven && rm -rf /var/lib/apt/lists/* |
||||
|
|
||||
|
WORKDIR /app |
||||
|
|
||||
|
# Create source directory |
||||
|
RUN mkdir -p src/main/java |
||||
|
|
||||
|
# Copy source and build files |
||||
|
COPY SeekToBeginningTest.java src/main/java/ |
||||
|
COPY pom.xml . |
||||
|
|
||||
|
# Compile and package |
||||
|
RUN mvn clean package -DskipTests |
||||
|
|
||||
|
# Run the test |
||||
|
ENTRYPOINT ["java", "-cp", "target/seek-test.jar", "SeekToBeginningTest"] |
||||
|
CMD ["kafka-gateway:9093"] |
||||
@ -0,0 +1,73 @@ |
|||||
|
import org.apache.kafka.clients.consumer.*; |
||||
|
import org.apache.kafka.common.TopicPartition; |
||||
|
import org.apache.kafka.common.serialization.ByteArrayDeserializer; |
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* Test program to reproduce the seekToBeginning() hang issue |
||||
|
* |
||||
|
* This simulates what Schema Registry does: |
||||
|
* 1. Create KafkaConsumer |
||||
|
* 2. Assign to partition |
||||
|
* 3. Call seekToBeginning() |
||||
|
* 4. Poll for records |
||||
|
* |
||||
|
* Expected behavior: Consumer should send ListOffsets and then Fetch requests |
||||
|
* Observed behavior: Consumer sends InitProducerId but not ListOffsets, then |
||||
|
* hangs |
||||
|
*/ |
||||
|
public class SeekToBeginningTest { |
||||
|
public static void main(String[] args) throws Exception { |
||||
|
String bootstrapServers = "localhost:9093"; |
||||
|
String topicName = "_schemas"; |
||||
|
|
||||
|
if (args.length > 0) { |
||||
|
bootstrapServers = args[0]; |
||||
|
} |
||||
|
|
||||
|
Properties props = new Properties(); |
||||
|
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); |
||||
|
props.put(ConsumerConfig.GROUP_ID_CONFIG, "test-seek-group"); |
||||
|
props.put(ConsumerConfig.CLIENT_ID_CONFIG, "test-seek-client"); |
||||
|
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); |
||||
|
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false"); |
||||
|
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); |
||||
|
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteArrayDeserializer.class); |
||||
|
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "45000"); |
||||
|
props.put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "60000"); |
||||
|
|
||||
|
System.out.println("[TEST] Creating KafkaConsumer connecting to " + bootstrapServers); |
||||
|
KafkaConsumer<byte[], byte[]> consumer = new KafkaConsumer<>(props); |
||||
|
|
||||
|
TopicPartition tp = new TopicPartition(topicName, 0); |
||||
|
List<TopicPartition> partitions = Arrays.asList(tp); |
||||
|
|
||||
|
System.out.println("[TEST] Assigning to partition: " + tp); |
||||
|
consumer.assign(partitions); |
||||
|
|
||||
|
System.out.println("[TEST] Calling seekToBeginning()..."); |
||||
|
long startTime = System.currentTimeMillis(); |
||||
|
consumer.seekToBeginning(partitions); |
||||
|
long seekTime = System.currentTimeMillis() - startTime; |
||||
|
System.out.println("[TEST] seekToBeginning() completed in " + seekTime + "ms"); |
||||
|
|
||||
|
System.out.println("[TEST] Starting poll loop (30 second timeout per poll)..."); |
||||
|
for (int i = 0; i < 3; i++) { |
||||
|
System.out.println("[POLL " + (i + 1) + "] Polling for records..."); |
||||
|
long pollStart = System.currentTimeMillis(); |
||||
|
ConsumerRecords<byte[], byte[]> records = consumer.poll(java.time.Duration.ofSeconds(30)); |
||||
|
long pollTime = System.currentTimeMillis() - pollStart; |
||||
|
System.out.println("[POLL " + (i + 1) + "] Got " + records.count() + " records in " + pollTime + "ms"); |
||||
|
|
||||
|
for (ConsumerRecord<byte[], byte[]> record : records) { |
||||
|
System.out.println(" [RECORD] offset=" + record.offset() + ", key.len=" + |
||||
|
(record.key() != null ? record.key().length : 0) + |
||||
|
", value.len=" + (record.value() != null ? record.value().length : 0)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
System.out.println("[TEST] Closing consumer..."); |
||||
|
consumer.close(); |
||||
|
System.out.println("[TEST] Done!"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
|
||||
|
<groupId>io.confluent.test</groupId> |
||||
|
<artifactId>seek-test</artifactId> |
||||
|
<version>1.0</version> |
||||
|
|
||||
|
<properties> |
||||
|
<maven.compiler.source>11</maven.compiler.source> |
||||
|
<maven.compiler.target>11</maven.compiler.target> |
||||
|
<kafka.version>3.6.0</kafka.version> |
||||
|
</properties> |
||||
|
|
||||
|
<dependencies> |
||||
|
<dependency> |
||||
|
<groupId>org.apache.kafka</groupId> |
||||
|
<artifactId>kafka-clients</artifactId> |
||||
|
<version>${kafka.version}</version> |
||||
|
</dependency> |
||||
|
<dependency> |
||||
|
<groupId>org.slf4j</groupId> |
||||
|
<artifactId>slf4j-simple</artifactId> |
||||
|
<version>2.0.0</version> |
||||
|
</dependency> |
||||
|
</dependencies> |
||||
|
|
||||
|
<build> |
||||
|
<plugins> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-compiler-plugin</artifactId> |
||||
|
<version>3.8.1</version> |
||||
|
</plugin> |
||||
|
<plugin> |
||||
|
<groupId>org.apache.maven.plugins</groupId> |
||||
|
<artifactId>maven-shade-plugin</artifactId> |
||||
|
<version>3.2.4</version> |
||||
|
<executions> |
||||
|
<execution> |
||||
|
<phase>package</phase> |
||||
|
<goals> |
||||
|
<goal>shade</goal> |
||||
|
</goals> |
||||
|
<configuration> |
||||
|
<transformers> |
||||
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> |
||||
|
<mainClass>SeekToBeginningTest</mainClass> |
||||
|
</transformer> |
||||
|
</transformers> |
||||
|
<finalName>seek-test</finalName> |
||||
|
</configuration> |
||||
|
</execution> |
||||
|
</executions> |
||||
|
</plugin> |
||||
|
</plugins> |
||||
|
</build> |
||||
|
</project> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue