unbridled-41 opened a new pull request, #11050:
URL: https://github.com/apache/rocketmq/pull/11050

   Closes #11049
   
   ### Problem / Evidence
   
   The v2 gRPC protocol defines `SendMessageResponse.entries` as one 
`SendResultEntry` per message of the request. The proxy sends an N-message 
request to the broker as **one** remoting batch send and returns a 
single-element `List<SendResult>` in both modes:
   
   - `LocalMessageService#sendMessage`: `msgList.size() > 1` collapses into one 
`MessageBatch`, one result.
   - `ClusterMessageService#sendMessage`: `sendMessageAsync(..., msgList, ...)` 
for N messages, one result (comma-joined per-message ids, first message's queue 
offset).
   
   `SendMessageActivity#convertToSendMessageResponse` iterates the result list 
one-to-one, so an N-message request gets a **1-entry** response. Every official 
v2 SDK validates the receipt count — rocketmq-clients Java `ProducerImpl#send0` 
fails the send future with `InternalErrorException("[Bug] due to an unknown 
reason from remote, received send receipt's quantity ... is not equal to sent 
message's quantity ...")` when `sendReceipts.size() != messages.size()`. The 
broker has already stored all N messages, the caller sees the send fail, and 
the SDK's automatic retry stores the whole batch again — a full duplicate batch.
   
   Deterministic regression test 
`SendMessageActivityTest#testConvertToSendMessageResponseExpandsBatchSendResult`
 (request with 3 messages, one `SEND_OK` batch `SendResult` with comma-joined 
ids and queue offset 10). Fails on unmodified `develop`:
   
   ```
   java.lang.AssertionError: one entry per request message must be returned 
expected:<3> but was:<1>
        at 
org.apache.rocketmq.proxy.grpc.v2.producer.SendMessageActivityTest.testConvertToSendMessageResponseExpandsBatchSendResult(SendMessageActivityTest.java:212)
   Tests run: 2, Failures: 1, Errors: 0, Skipped: 1   (develop @ ff8f6f74c + 
test only, 2026-09-05, JDK 8)
   ```
   
   ### Root cause / Fix
   
   The response conversion does not know that one `SendResult` can represent N 
request messages.
   
   Fix: `SendMessageActivity#expandBatchSendResult` expands a single batch 
result into per-message results before the existing per-result conversion loop, 
mirroring the client-side expansion in `ProduceAccumulator#splitSendResults` — 
split the comma-joined `msgId`/`offsetMsgId`, `queueOffset + i` per entry, 
preserve `transactionId`/`regionId`/`recallHandle`, and reuse the batch result 
for every message when the broker returned no per-message ids (inner-batch 
message responses). The request is available at the conversion site, so local 
and cluster mode are fixed at once.
   
   ### Priority
   
   PRIORITY = 76(影响 32 + 波及范围 14 + 可复现 16 + 维护价值 14),FIX_CONFIDENCE = 82。
   
   - 影响 32/40: batch sends through the proxy fail in the SDK although the 
broker persisted the batch; automatic retries duplicate the entire batch — 
user-visible data correctness issue.
   - 波及范围 14/20: all v2 SDKs (Java/Go/C++/C#) sending `SendMessageRequest` with 
more than one message through the proxy; the client-side precedent 
(`ProduceAccumulator`) shows batch sends are a real, used path.
   - 可复现 16/20: deterministic unit test at the conversion boundary; the 
end-to-end receipt-count check in the SDKs is a hard failure.
   - 维护价值 14/20: restores the documented protocol contract (`entries` 
one-to-one with `messages`); the expansion algorithm is already established in 
the client module.
   
   ### Tests
   
   - Regression test added: 
`SendMessageActivityTest#testConvertToSendMessageResponseExpandsBatchSendResult`
 (fails before the fix as shown above).
   - After the fix (`develop @ ff8f6f74c` + this change, 2026-09-05, JDK 8):
   
   ```
   mvn -pl proxy test -Dtest=SendMessageActivityTest
   Tests run: 13, Failures: 0, Errors: 0, Skipped: 0 — BUILD SUCCESS   (grpc 
v2: 12, remoting activity: 1)
   mvn -pl proxy test
   Tests run: 318, Failures: 0, Errors: 0, Skipped: 3 — BUILD SUCCESS
   ```
   
   Note: this test cannot run under a local JDK 21 (pre-existing environmental 
baseline: Mockito/ByteBuddy "Unsupported class file major version 65" affects 
the whole test class before any change); the CI matrix builds and tests with 
JDK 8, where all runs above were performed.
   
   ### Risk
   
   Low. The expansion only triggers when the result list holds exactly one 
result while the request carries at least two messages — a shape that today 
always comes from the batch send path; single-message sends and 
already-per-message result lists pass through untouched. Per-message offsets 
are derived exactly as the remoting client does (`queueOffset + i`), and the 
fallback for id-less batch results matches 
`ProduceAccumulator#splitSendResults` semantics, so v2 SDK receipt processing 
stays consistent with the remoting client behavior.
   


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