RockteMQ-AI commented on code in PR #2619:
URL: 
https://github.com/apache/rocketmq-dashboard/pull/2619#discussion_r3859451615


##########
server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQController.java:
##########
@@ -95,22 +97,25 @@ public Result<PageResult<DLQMessageVO>> 
listDLQMessages(@PathVariable String gro
     }
 
     @GetMapping("/export-excel")
-    public ResponseEntity<byte[]> exportDLQExcel(@RequestParam String 
instanceId,
-                                                 @RequestParam String 
groupName,
-                                                 @RequestParam(required = 
false) Long startTime,
-                                                 @RequestParam(required = 
false) Long endTime,
-                                                 @Size(max = 
MAX_SELECTED_MESSAGES,
-                                                         message = "At most 
100 msgIds are allowed per export")
-                                                 @RequestParam(required = 
false) List<String> msgIds) {
-        DLQExcelExportResultVO result = dlqService.exportExcel(instanceId, 
groupName, startTime, endTime, msgIds);
-        return ResponseEntity.ok()
-                .header(HttpHeaders.CONTENT_DISPOSITION,
-                        attachmentDisposition("dlq-" + 
sanitizeForFilename(groupName) + ".xlsx").toString())
-                .header(HEADER_EXPORT_TRUNCATED, 
String.valueOf(result.isTruncated()))
-                .header(HEADER_EXPORT_FAILED_QUEUES, 
String.valueOf(result.getFailedQueueCount()))
-                .header(HEADER_EXPORT_LIMIT, String.valueOf(result.getLimit()))
-                .contentType(MediaType.parseMediaType(EXCEL_MEDIA_TYPE))
-                .body(result.getData());
+    public ResponseEntity<Void> exportDLQExcel(@RequestParam String instanceId,
+                                               @RequestParam String groupName,
+                                               @RequestParam(required = false) 
Long startTime,
+                                               @RequestParam(required = false) 
Long endTime,
+                                               @Size(max = 
MAX_SELECTED_MESSAGES,
+                                                       message = "At most 100 
msgIds are allowed per export")
+                                               @RequestParam(required = false) 
List<String> msgIds,
+                                               HttpServletResponse response) 
throws IOException {
+        // Stream the workbook straight to the response body so it is never 
buffered in the heap.
+        response.setContentType(EXCEL_MEDIA_TYPE);
+        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
+                attachmentDisposition("dlq-" + sanitizeForFilename(groupName) 
+ ".xlsx").toString());

Review Comment:
   **[Warning]** Response headers set after streaming write.\n\nThe metadata 
headers (`X-DLQ-Export-Truncated`, `X-DLQ-Export-FailedQueues`, 
`X-DLQ-Export-Limit`) are set **after** `dlqService.exportExcel()` writes to 
`response.getOutputStream()`. In a real servlet container, if the Excel data 
exceeds the response buffer (typically 8 KB for Tomcat), the buffer 
auto-flushes during the write and the response becomes committed — subsequent 
`setHeader()` calls are silently ignored.\n\nFor large exports, the client 
would lose the completeness metadata headers, which defeats their purpose (the 
client uses them to detect truncation and failed queues).\n\n**Suggested fix:** 
Set all headers **before** the streaming write. Since the metadata is only 
available after the export completes, consider a two-phase 
approach:\n```java\n// Phase 1: write to a temp buffer / piped stream to 
collect metadata\n// Phase 2: set headers from metadata\n// Phase 3: pipe 
buffer to response output\n```\nOr restr
 ucture `exportExcel` to return metadata before writing the body.



##########
server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java:
##########
@@ -335,23 +334,24 @@ public DLQExcelExportResultVO exportExcel(String 
instanceId, String groupName, L
         DeadLetterScanResult scanResult = collectDeadLetters(instanceId, 
dlqTopic, begin, end, RESEND_HARD_CAP);
         Set<String> selected = msgIds == null ? Collections.emptySet()
                 : new java.util.HashSet<>(msgIds);
-        List<DLQMessageVO> messages = scanResult.messages().stream()
+        List<DLQMessageExcelRow> rows = scanResult.messages().stream()
                 .filter(message -> selected.isEmpty() || 
selected.contains(message.getMsgId()))
                 .map(this::toExportVO)
+                .map(DLQMessageExcelRow::from)
                 .toList();
-        byte[] data;
         try {
-            ByteArrayOutputStream output = new ByteArrayOutputStream();
-            com.alibaba.excel.EasyExcel.write(output, DLQMessageExcelRow.class)
+            // Stream straight to the caller's OutputStream so the whole 
workbook is never buffered
+            // in the heap (the export is capped at RESEND_HARD_CAP messages, 
but large snapshots can
+            // still be several MB).
+            com.alibaba.excel.EasyExcel.write(out, DLQMessageExcelRow.class)
                     .sheet("DLQ")
-                    
.doWrite(messages.stream().map(DLQMessageExcelRow::from).toList());
-            data = output.toByteArray();
+                    .doWrite(rows);
+            out.flush();
         } catch (Exception e) {
             log.warn("Failed to build Excel export for group {}: {}", 
groupName, e.getMessage());

Review Comment:
   **[Info]** Redundant flush. `out.flush()` is called here (line 351) and 
again in the controller (`response.getOutputStream().flush()`). The double 
flush is harmless but unnecessary — one flush at the controller level is 
sufficient.



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