apache / apache/rocketmq

[Bug] Proxy gRPC batch send returns one receipt for N messages, so SDKs fail the send although the broker stored the batch

Open
#11,049 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
22.6k
Forks
12k
Avg merge
3d 1h
Merged PRs (30d)
27

Description

### Before Creating the Bug Report

- [x] I found a bug, not just a question.
- [x] I searched open GitHub Issues and pull requests and found no duplicate.
- [x] I confirmed that this bug belongs to Apache RocketMQ.

### Runtime platform environment

All platforms; reproduced with a deterministic unit test on the current `develop` branch.

### RocketMQ version

`develop` at `ff8f6f74c`

### JDK Version

All

### Describe the Bug

The v2 gRPC protocol defines `SendMessageResponse.entries` as one `SendResultEntry` per message of the request. The proxy, however, sends an N-message `SendMessageRequest` to the broker as **one** remoting batch send and forwards the single batch `SendResult` to `SendMessageActivity#convertToSendMessageResponse`, which builds exactly **one** response entry:

- `LocalMessageService#sendMessage` collapses `msgList.size() > 1` into one `MessageBatch` and returns a single-element `List`.
- `ClusterMessageService#sendMessage` calls `sendMessageAsync(..., msgList, ...)` for `msgList.size() != 1`, which also returns one `SendResult` (comma-joined per-message ids, first message's queue offset).
- `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()`. So although the broker has **already stored all N messages**, the caller sees the send fail — and the SDK's automatic retry sends the whole batch again, duplicating every message.

### Steps to Reproduce

1. Send a `SendMessageRequest` with 3 messages through the proxy (gRPC v2, local or cluster mode).
2. Observe the broker stored 3 messages, but `SendMessageResponse.entries` has size 1 (offset = only the first message's, messageId = comma-joined batch ids).
3. rocketmq-clients Java/Go/C++/C# producers reject the response with the receipt-quantity error and retry, storing the batch a second time.

### What Did You Expect to See?

`SendMessageResponse.entries` must contain one entry per request message, with the per-message `messageId` and `queueOffset + i`, the same way the remoting client expands batch results (`ProduceAccumulator#splitSendResults`).

### What Did You See Instead?

One entry for the whole batch; SDKs fail the send although it was persisted, and retries duplicate the batch.

### Additional Context

The client module already contains the intended expansion algorithm (`ProduceAccumulator#splitSendResults`: split comma-joined `msgId`/`offsetMsgId`, `queueOffset + i` per entry, and reuse the single result for inner-batch-message responses without per-message ids). Applying the same expansion in `SendMessageActivity#convertToSendMessageResponse` (where the original request is available) fixes local and cluster mode at once, and a regression test in `SendMessageActivityTest` fails on unmodified `develop`.

### Corresponding PR

- PR apache/rocketmq#11050

Contributor guide

Open the contributing guide

Research direction

Start in SendMessageActivity#convertToSendMessageResponse and read SendMessageActivityTest, then compare the existing ProduceAccumulator#splitSendResults behavior. Run the regression test for a three-message gRPC v2 request in local and cluster modes. Done means the response has one receipt per request message with the expected message IDs and queue offsets, without breaking inner-batch responses.

Written by the indexing model from the issue text.

Assessment

Tech stack
grpc, java
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.