[Bug] Transactional message escape retry uses 2 ^ n (XOR) instead of exponential backoff, including a zero-delay retry
- 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 asking a question, which should be created in [GitHub Discussions](https://github.com/apache/rocketmq/discussions).
- [x] I have searched the [GitHub Issues](https://github.com/apache/rocketmq/issues) and [GitHub Discussions](https://github.com/apache/rocketmq/discussions) of this repository and believe 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
- OS: Linux
- Component: Broker (`TransactionalMessageServiceImpl`)
### RocketMQ version
- branch: develop
- Git commit id: e348efa66
### JDK Version
JDK 8
### Describe the Bug
In `TransactionalMessageServiceImpl#check`, when a broker configured with `enableSlaveActingMaster` fails to escape a transactional half message, the retry delay is computed with the XOR operator instead of exponentiation:
```java
if (escapeFailCnt < MAX_RETRY_TIMES_FOR_ESCAPE) {
escapeFailCnt++;
Thread.sleep(100L * (2 ^ escapeFailCnt)); // '^' is XOR in Java, not power
}
```
The actual sleep sequence for `escapeFailCnt` = 1..10 is `300, 0, 100, 600, 700, 400, 500, 1000, 1100, 800` ms instead of the intended exponential `200, 400, 800, ...`. In particular the second consecutive failure sleeps **0 ms**, so the check loop immediately hammers the store with another full put attempt, defeating the purpose of the backoff (this code was introduced with the escaping feature in #5012 / ISSUE #5012).
### Steps to Reproduce
`Thread.sleep(100L * (2 ^ 2))` evaluates to `sleep(0)` because `2 ^ 2 == 0`. Print `100L * (2 ^ n)` for n = 1..10 to see the non-monotonic sequence.
### What Did You Expect to See?
An exponential backoff between escape retries: `100L * (1 << escapeFailCnt)` ms, i.e. 200, 400, 800, ... ms.
### What Did You See Instead?
A non-monotonic sequence produced by XOR, including a 0 ms delay, so failed escape attempts are retried without any backoff.
### Additional Context
I extracted the computation into a small package-private helper so the backoff sequence is unit-testable, and will submit a PR with the test.
Contributor guide
Research direction
Start at TransactionalMessageServiceImpl#check and trace the escape retry path for brokers with enableSlaveActingMaster. Extract the backoff computation into the mentioned package-private helper, then add a unit test covering the expected exponential sequence and the absence of zero-delay retries.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100