From 0de33811b99cb50b03d688556cc68bc04d4efaf8 Mon Sep 17 00:00:00 2001 From: Igor Melnichenko Date: Wed, 5 Aug 2026 01:43:26 +0300 Subject: [PATCH] Skip an empty read batch instead of dropping the rest of the response addBatches returned as soon as it saw a batch with no messages, so every batch after it in the same ReadResponse was silently discarded: the messages never reached the user and the read futures of those batches never completed, which also stopped ReadSession.onReadResponse from requesting more data. Skip the offending batch and keep processing the rest of the response. --- .../topic/read/impl/ReadPartitionSession.java | 2 +- .../read/impl/ReadPartitionSessionTest.java | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 topic/src/test/java/tech/ydb/topic/read/impl/ReadPartitionSessionTest.java diff --git a/topic/src/main/java/tech/ydb/topic/read/impl/ReadPartitionSession.java b/topic/src/main/java/tech/ydb/topic/read/impl/ReadPartitionSession.java index 0a055a0e3..3fd8099ff 100644 --- a/topic/src/main/java/tech/ydb/topic/read/impl/ReadPartitionSession.java +++ b/topic/src/main/java/tech/ydb/topic/read/impl/ReadPartitionSession.java @@ -92,7 +92,7 @@ public CompletableFuture addBatches(List delivered = Collections.synchronizedList(new ArrayList<>()); + + ReadPartitionSession reader = new ReadPartitionSession("test", session, partition, 0) { + @Override + CompletableFuture handleDataReceivedEvent(DataReceivedEvent event) { + event.getMessages().forEach(message -> delivered.add(message.getOffset())); + return CompletableFuture.completedFuture(null); + } + }; + + CompletableFuture batchesRead = reader.addBatches( + Arrays.asList(emptyProtoBatch(), rawProtoBatch(1), rawProtoBatch(2)) + ); + + batchesRead.get(); + Assert.assertEquals(Arrays.asList(1L, 2L), delivered); + } + + private static YdbTopic.StreamReadMessage.ReadResponse.Batch emptyProtoBatch() { + return YdbTopic.StreamReadMessage.ReadResponse.Batch.newBuilder() + .setCodec(Codec.RAW) + .setProducerId("producer") + .build(); + } + + private static YdbTopic.StreamReadMessage.ReadResponse.Batch rawProtoBatch(long offset) { + return YdbTopic.StreamReadMessage.ReadResponse.Batch.newBuilder() + .setCodec(Codec.RAW) + .setProducerId("producer") + .addMessageData( + YdbTopic.StreamReadMessage.ReadResponse.MessageData.newBuilder() + .setOffset(offset) + .setSeqNo(offset) + .setData(ByteString.copyFromUtf8("data")) + .build() + ) + .build(); + } +}