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

   ### Before Creating the Bug Report
   
   - [x] I found a bug, not just asking a question.
   - [x] I searched open/closed issues and pull requests for `asyncSendEnable`, 
`asyncPutMessageFuture`, exceptional completion, and send timeout, and found no 
equivalent report.
   - [x] I confirmed the affected code is in Apache RocketMQ.
   
   ### Runtime platform environment
   
   Deterministic broker unit test on Windows; the control-flow defect is 
platform independent.
   
   ### RocketMQ version
   
   `develop` at `bc33e8e4d7b25089af5f51bc669bdfedabfebe7d`.
   
   ### JDK Version
   
   Amazon Corretto 8u432 for the regression test.
   
   ### Describe the Bug
   
   When `asyncSendEnable=true`, `SendMessageProcessor` returns `null` 
immediately and relies on the `MessageStore` future to send the response later. 
Both the single-message and batch paths attach only `thenAcceptAsync(...)` to 
that future.
   If `asyncPutMessage(...)` / `asyncPutMessages(...)` completes exceptionally, 
the consumer passed to `thenAcceptAsync` is never invoked. Because the 
processor already returned `null`, no `doResponse(...)` path remains: the 
client receives no broker response and waits until an outer remoting timeout or 
connection teardown. The after-send hook is skipped as well.
   
   The single-message branch and the batch branch have the same shape:
   
   ```java
   asyncPutMessageFuture.thenAcceptAsync(putMessageResult -> {
       RemotingCommand responseFuture = handlePutMessageResult(...);
       if (responseFuture != null) {
           doResponse(ctx, request, responseFuture);
       }
       sendMessageCallback.onComplete(sendMessageContext, response);
   }, executor);
   return null;
   ```
   
   This is an observable asynchronous-completion gap, not just a theoretical 
null check. The store future contract can propagate exceptional completion from 
lower async stages; for example `CommitLog#handleDiskFlushAndHA` composes flush 
and HA futures with `thenCombine`.
   
   ### Steps to Reproduce
   
   1. Enable async send in a `SendMessageProcessorTest` fixture.
   2. Make `MessageStore.asyncPutMessage(...)` return a 
`CompletableFuture<PutMessageResult>` completed exceptionally with 
`RuntimeException("store write failed")`.
   3. Invoke `processRequest` with a normal `SEND_MESSAGE` request and capture 
`channel.writeAndFlush`.
   4. `processRequest(...)` returns `null`, as expected for async mode.
   5. Wait up to one second for a response.
   
   On the unmodified baseline the regression fails deterministically:
   
   ```text
   Tests run: 1, Failures: 0, Errors: 1
   ConditionTimeoutException: response was not fulfilled within 1 seconds
   ```
   
   The preceding 10 reactor modules succeed; only this broker regression fails.
   
   ### What Did You Expect to See?
   
   An exceptional store future should complete the request promptly with 
`SYSTEM_ERROR`, log the original throwable on the broker, and execute the 
normal after-send hook exactly once. The client should not have to discover a 
completed store failure through a later request timeout.
   
   ### What Did You See Instead?
   
   No response is written at all. The client remains pending until external 
timeout/connection handling terminates the request.
   
   ### Proposed scope
   
   Handle both single-message and batch async-send futures symmetrically. 
Preserve all existing success/result-code behavior, synchronous-send behavior, 
metrics, and protocol formats. Add deterministic regressions for exceptional 
completion and retain existing success coverage.
   


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