ymwneu opened a new issue, #11215:
URL: https://github.com/apache/rocketmq/issues/11215

   ### Before Creating the Bug Report
   
   - [x] I found a bug, not just asking a question, which should be created in 
[GitHub Discussions](https://github.com/apache/rocketmq/discussions).
   
   - [x] I have searched the [GitHub 
Issues](https://github.com/apache/rocketmq/issues) and [GitHub 
Discussions](https://github.com/apache/rocketmq/discussions)  of this 
repository and believe that this is not a duplicate.
   
   - [x] I have confirmed that this bug belongs to the current repository, not 
other repositories of RocketMQ.
   
   
   ### Runtime platform environment
   
   centos
   
   ### RocketMQ version
   
   5.5.1
   
   ### JDK Version
   
   jdk 8
   
   ### Describe the Bug
   
   When a consumer using CONSUME_FROM_LAST_OFFSET starts on a brand-new 
topic/queue that has no stored consumer offset, the broker can permanently skip 
the very first message (offset 0).
   QUERY_CONSUMER_OFFSET initializes the start offset only when the first 
message is already in the page cache: the condition is roughly minOffset <= 0 
&& checkInMemByConsumeOffset(topic, queueId, 0, 1). On a freshly created, 
still-empty queue offset 0 is not yet in memory, so the broker returns 
QUERY_NOT_FOUND. The client then falls back to a separate GET_MAX_OFFSET 
request to decide where to start. These two requests are not atomic: if a 
producer appends the first message in between, GET_MAX_OFFSET now returns 1, 
the consumer pins its start offset at 1, and the message at offset 0 is never 
consumed.
     The same checkInMemByConsumeOffset-only logic (and therefore the same 
race) also exists in PopMessageProcessor#getInitOffset and 
BroadcastOffsetManager#getOffset.
   
   ### Steps to Reproduce
   
   1. Create a brand-new topic/queue with no committed consumer offset.
     2. Start a consumer group configured with CONSUME_FROM_LAST_OFFSET and let 
it issue QUERY_CONSUMER_OFFSET while the queue is still empty (broker replies 
QUERY_NOT_FOUND).
     3. Immediately after that reply — before the client's follow-up 
GET_MAX_OFFSET lands — have a producer send exactly one message (it becomes 
offset 0, max offset becomes 1).
     4. Let the consumer complete its GET_MAX_OFFSET fallback and begin 
consuming.
   
     To make the timing window easy to hit, insert a short delay between the 
client's QUERY_CONSUMER_OFFSET and GET_MAX_OFFSET, and send the first message 
during that delay.
   
   ### What Did You Expect to See?
   
   The consumer starts at offset 0 and receives the first message. For a 
brand-new queue with no stored offset, "consume from last offset" should 
resolve to offset 0 (the last offset of an empty queue is 0), so the first 
message that arrives is delivered rather than skipped.
   
   ### What Did You See Instead?
   
   The consumer's start offset is pinned at 1 and the message at offset 0 is 
skipped forever. Because the offset is then committed at 1, the message is 
never redelivered — it is silently lost from that consumer group's perspective.
   
   ### Additional Context
   
   _No response_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to