tju-yxq opened a new issue, #1415:
URL: https://github.com/apache/rocketmq-dashboard/issues/1415

   ## Bug Report
   
   ### 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 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
   
   OS: Ubuntu 20.04 / Any OS running RocketMQ Studio
   
   ### RocketMQ version
   
   branch: rocketmq-studio
   version: 5.3.2+
   Git commit id: f727341
   
   ### JDK Version
   
   OpenJDK 21
   
   ### Describe the Bug
   
   `RocketMQDLQProvider.resendOne()` creates a new `Message` for resend but 
only copies `body`, `tags`, and `keys` from the original dead-letter message. 
It does **not** copy the original message's user properties. When a dead-letter 
message is resent to the target topic, all business-level user properties 
(trace IDs, correlation IDs, custom headers, etc.) are lost.
   
   ```java
   Message message = new Message(destination, deadLetter.getBody());
   if (StringUtils.hasText(deadLetter.getTags())) {
       message.setTags(deadLetter.getTags());
   }
   if (StringUtils.hasText(deadLetter.getKeys())) {
       message.setKeys(deadLetter.getKeys());
   }
   message.putUserProperty(ORIGIN_MESSAGE_ID_PROPERTY, deadLetter.getMsgId());
   message.putUserProperty(ORIGIN_TOPIC_PROPERTY, deadLetter.getTopic());
   // Missing: copy of deadLetter.getProperties() (user properties)
   ```
   
   ### Impact
   
   1. **Trace IDs lost**: Messages that carry distributed trace IDs (e.g., 
`traceId`, `spanId`) as user properties lose their trace context after resend, 
breaking downstream tracing.
   
   2. **Correlation IDs lost**: Business-level correlation IDs used for 
deduplication or ordering are lost, potentially causing duplicate processing or 
ordering violations in the consumer.
   
   3. **Custom headers lost**: Application-specific headers (e.g., 
`contentType`, `priority`, `tenantId`) are stripped, causing consumers to 
misinterpret or reject the resent message.
   
   4. **RocketMQ system properties**: The 
`MessageConst.PROPERTY_DLQ_ORIGIN_TOPIC` and `PROPERTY_RETRY_TOPIC` are not 
copied either, though these are managed by the broker and may not need manual 
copying.
   
   ### Steps to Reproduce
   
   1. Produce a message with user properties: `msg.putUserProperty("traceId", 
"abc-123"); msg.putUserProperty("tenantId", "tenant-A");`
   2. Let the message enter the dead-letter queue (exhaust retries).
   3. In RocketMQ Studio, trigger a DLQ resend.
   4. Consume the resent message and inspect its properties.
   5. Observe: `traceId` and `tenantId` are missing.
   
   ### What Did You Expect to See?
   
   The resent message should carry all user properties from the original 
dead-letter message, plus the two Studio-specific provenance properties 
(`studio_dlq_origin_message_id`, `studio_dlq_origin_topic`).
   
   ### What Did You See Instead?
   
   Only `studio_dlq_origin_message_id` and `studio_dlq_origin_topic` are 
present. All original user properties are lost.
   
   ### Additional Context
   
   **Affected file**: 
`server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java`,
 method `resendOne()` at approximately line 155.
   
   **Fix approach**:
   
   After creating the new `Message` and setting tags/keys, copy all user 
properties from the dead-letter message, skipping RocketMQ system properties 
(those in `MessageConst` reserved properties) to avoid conflicts:
   
   ```java
   // Copy user properties from the original message, skipping system-reserved 
keys
   Map<String, String> userProperties = deadLetter.getUserProperties();
   if (userProperties != null) {
       for (Map.Entry<String, String> entry : userProperties.entrySet()) {
           String key = entry.getKey();
           if (!MessageConst.STRING_HASH_SET.contains(key) && 
!key.startsWith(MessageConst.PROPERTY_ORIGIN_MESSAGE_ID)) {
               message.putUserProperty(key, entry.getValue());
           }
       }
   }
   ```
   
   This adds approximately 10 lines. No existing logic is deleted.
   


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