SEPURI-SAI-KRISHNA commented on issue #12332:
URL: https://github.com/apache/seatunnel/issues/12332#issuecomment-5690466293

   Following up on my own report with one refinement, because I went to write 
the patch and found that the fix cannot go where it would be most convenient.
   
   The tempting place is the call site, guarding the fallback in 
`RocketMqSourceSplitEnumerator`:
   
   ```java
   case CONSUME_FROM_GROUP_OFFSETS:
       Map<MessageQueue, Long> groupOffsets = listConsumerGroupOffsets(queues);
       if (groupOffsets.isEmpty()) { ... first offset ... }
   ```
   
   That does not work, because an empty map there has three different causes 
and the enumerator cannot tell them apart:
   
   1. the topic genuinely does not exist, so a cold start is correct;
   2. the admin lookup failed transiently on a missing route, which is the 
defect in this issue;
   3. the lookup **succeeded** and the filter at the end of `currentOffsets`, 
`.filter(messageQueue -> messageQueues.contains(messageQueue))`, removed 
everything, which happens for a newly discovered queue that has no entry in the 
consume stats yet.
   
   Case 3 is legitimate and common with partition discovery enabled, and 
starting such a queue from the first offset is the right behavior. Any guard at 
the call site that refuses to fall back on an empty map would break it. So the 
distinction has to be drawn inside `currentOffsets`, which is the only place 
that knows whether the admin call threw or returned and was filtered.
   
   That constrains the fix in a way worth agreeing before I write it. Inside 
`currentOffsets` the two exception cases are separable, since 
`RocketMqAdminUtil.topicExist` at line 186 answers exactly the question that 
splits case 1 from case 2, and the existing behavior is preserved either way: a 
genuinely absent topic still returns an empty map and still cold-starts, while 
an existing topic whose route is briefly unreadable stops being reported as 
"nothing committed". Case 3 is untouched because it never enters the catch 
block.
   
   The open question is what should happen in case 2 once it is 
distinguishable: retry the lookup and then fail if it does not recover, or fail 
immediately. Failing is safe in the sense that rewinding and silently 
re-delivering a topic is worse than a visible error, but it does turn a 
transient condition into a job failure, so it is a judgement call rather than a 
purely mechanical fix.
   
   There is also a testability constraint I would rather surface than work 
around quietly. `currentOffsets` builds its admin client internally through 
`startMQAdminTool(config)`, so there is no seam to inject a failing client in a 
unit test. `RocketMqSourceSplitEnumeratorTest` already uses 
`Mockito.mockStatic(RocketMqAdminUtil.class)`, but that mocks the very class 
the fix would live in, so it cannot cover this. Introducing a small seam would 
make the fix properly testable, at the cost of touching a little more than the 
defect strictly requires.
   
   I am happy to implement whichever combination is preferred. I am holding off 
on the PR only because the retry-versus-fail choice and the seam are decisions 
I would rather not make unilaterally in production connector code on a 
data-correctness path.
   


-- 
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