[Bug] Delay messages are delivered with internal properties leaked into propertiesString (ScheduleMessageService#messageTimeUp)
Before Creating the Bug Report
- I found a bug, not just asking a question, which should be created in GitHub Discussions.
- I have searched the GitHub Issues and GitHub Discussions of this repository and believe that this is not a duplicate.
- I have confirmed that this bug belongs to the current repository, not other repositories of RocketMQ.
Runtime platform environment
Linux, JDK 21, develop (ff8f6f74c)
RocketMQ version
5.x develop
Describe the Bug
ScheduleMessageService#messageTimeUp (broker/src/main/java/org/apache/rocketmq/broker/schedule/ScheduleMessageService.java) encodes the delivered message's propertiesString before the internal properties are cleared:
msgInner.setPropertiesString(MessageDecoder.messageProperties2String(msgExt.getProperties())); // line 344 — encode
...
MessageAccessor.clearProperty(msgInner, MessageConst.PROPERTY_DELAY_TIME_LEVEL); // line 353 — clear after
MessageAccessor.clearProperty(msgInner, MessageConst.PROPERTY_TIMER_DELIVER_MS);
MessageAccessor.clearProperty(msgInner, MessageConst.PROPERTY_TIMER_DELAY_SEC);The propertiesString is what actually gets persisted in the commitlog and decoded on the consumer side, so every delay-level message delivered by ScheduleMessageService still carries DELAY_TIME_LEVEL (and TIMER_DELIVER_MS/TIMER_DELAY_SEC when the producer used timer properties) on the wire, while the broker-side property map no longer has them. The property map and the wire data disagree; SQL92 property filtering and user code see stale internal properties.
This is the exact defect class fixed for the timer-wheel path in #10972 / commit e533b663f (TimerMessageStore#convertMessage now encodes after clearing). The same pattern in ScheduleMessageService#messageTimeUp predates it (old unmerged PR #4190 tried to address it in 2022) and was not covered by that fix.
Steps to Reproduce
- Send a message with
setDelayTimeLevel(n). - When the delay expires,
messageTimeUpre-writes it into the real topic. - Consume the message:
message.getProperties()/getProperty("DELAY_TIME_LEVEL")(decoded frompropertiesString) still returns the internal delay properties.
Expected Behavior
The delivered message's propertiesString must be encoded after the internal properties are cleared, so the property map and the wire data are consistent and no internal properties leak to consumers.
Corresponding PR
- Fix PR: #11038 (linked with
Closes #11037in the PR description; contains the regression test that fails before the fix and passes after it).
Source: apache/rocketmq