Skip to content

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

Description

@unbridled-41

Before Creating the Bug Report

  • I found a bug, not just a question.
  • I searched open GitHub Issues and pull requests and found no duplicate.
  • 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<SendResult>.
  • 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions