lizhimins opened a new issue, #1335:
URL: https://github.com/apache/rocketmq-clients/issues/1335

   ### Before Creating the Bug Report
   
   - [X] I found a bug, not just asking a question, which should be created in 
[GitHub Discussions](https://github.com/apache/rocketmq-clients/discussions).
   - [X] I have searched the [GitHub 
Issues](https://github.com/apache/rocketmq-clients/issues) of this repository 
and believe that this is not a duplicate.
   - [X] I have confirmed that this bug belongs to the current repository, not 
other repositories of RocketMQ.
   
   ### Runtime platform environment
   
   Linux x86_64 / macOS arm64
   
   ### RocketMQ description
   
   Apache rocketmq-clients C++ (verified against master `3a8ec615`)
   
   ### RocketMQ Client version
   
   cpp-5.0.3, cpp-5.1.0 and current master
   
   ### Run or compilation description
   
   Bazel 6.6.0
   
   ### Bug description
   
   The synchronous producer APIs can block the calling thread indefinitely. 
`Configuration::withRequestTimeout()` does not bound them.
   
   **1. `SendMessage` has no gRPC deadline.** `send()` is the only RPC in the 
`ClientManager` interface without a `timeout` parameter:
   
   | RPC | `timeout` parameter |
   | --- | --- |
   | `ack(...)` | yes |
   | `changeInvisibleDuration(...)` | yes |
   | `endTransaction(...)` | yes |
   | `recallMessage(...)` | yes |
   | `send(...)` | **no** |
   
   Consequently `ClientManagerImpl::send()` 
(`cpp/source/client/ClientManagerImpl.cpp:288`) never calls `set_deadline()`, 
and `RpcClientImpl::asyncSend()` passes the context straight to the stub 
without one. None of the 14 `set_deadline()` call sites in the tree is on the 
`SendMessage` path. `requestTimeout()` is only consumed by `endTransaction` and 
`recallMessage` in `ProducerImpl`. A stalled broker therefore leaves the 
completion callback pending indefinitely.
   
   **2. All four synchronous wait sites use `absl::CondVar::Wait()` with no 
deadline**, and three also drop wakeups:
   
   | Site | Completion guard | Deadline |
   | --- | --- | --- |
   | `ProducerImpl::send()` sync (`ProducerImpl.cpp:249`) | correct | **none** |
   | `endTransaction0()` (`:463`) | **none at all** | **none** |
   | `recallMessage()` (`:579`) | **no flag exists** | **none** |
   | `getPublishInfo()` (`:641`) | **racy — read outside the mutex** | **none** 
|
   
   `getPublishInfo()` is the worst:
   
   ```cpp
   while (!complete) {          // read without holding mtx
     absl::MutexLock lk(mtx.get());
     cv->Wait(mtx.get());
   }
   ```
   
   This is both a data race and a lost wakeup:
   
   ```
   T1: evaluates !complete -> true
   T2: locks mtx, sets complete = true, SignalAll() (no waiter yet), unlocks
   T1: locks mtx, Wait() -> blocks forever, nobody left to signal
   ```
   
   So this is a permanent hang, not merely a slow call. `endTransaction0()` and 
`recallMessage()` do not check a completion flag at all (`recallMessage()` does 
not even declare one), so an already-completed callback strands the caller 
unconditionally.
   
   `getPublishInfo()` only exposes the window when the route is not cached, 
since `getPublishInfoAsync()` invokes the callback inline on a cache hit — 
which is why it does not reproduce on every send.
   
   Verified experimentally: with the current code a unit test that stalls the 
route query never returns; the test process could not even be reclaimed by its 
own timeout, because the hung thread cannot be joined.
   
   ### Steps to reproduce
   
   1. Make the route query (or the broker) stall without ever completing.
   2. Call the synchronous `Producer::send()` for a topic whose route is not 
yet cached.
   3. The calling thread never returns, regardless of `withRequestTimeout()`.
   
   ### What did you expect to see?
   
   `withRequestTimeout()` bounds normal `SendMessage` RPCs and the outer 
synchronous waits, so `send()` returns an error (e.g. `RequestTimeout`) within 
a bounded time.
   
   ### What did you see instead?
   
   The calling thread blocks indefinitely; no timeout applies at either the 
gRPC layer or the outer synchronous wait.
   
   ### Additional context
   
   I have a fix and will open a PR referencing this issue.
   


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