unbridled-41 opened a new pull request, #4950:
URL: https://github.com/apache/rocketmq-dashboard/pull/4950
## Problem
The dead-letter message list of a group reports a complete-looking list and
a complete-looking total even when the scan behind it was cut short. A queue
the broker refuses to answer disappears from the list with no trace, and a
group with more than 5000 dead letters inside the queried window silently loses
the rest behind an unreachable page range.
The two export endpoints of the same provider already carry the flags that
describe this; the list endpoint, which is the screen an operator actually
recovers from, does not.
## Evidence
Base commit `1ef5d860`,
`server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java`.
* `:349-356` (base) — `listMessages` slices its page out of a bounded scan
and returns a plain page:
```java
List<DLQMessageVO> all = collectDeadLetters(instanceId, dlqTopic, begin,
end, RESEND_HARD_CAP)
.messages().stream()
.map(this::toExportVO)
.toList();
...
return PageResult.of(all.subList(from, to), all.size(), page, pageSize);
```
The `DeadLetterScanResult` produced at `:349` (`record` at `:701-706`)
carries `truncated()` and `failedQueueCount()`, and neither is read here.
* `:83` (base) — `RESEND_HARD_CAP = 5000`; the scan sets `truncated = true`
at `:470` and `:513` when it stops at the cap, and increments
`failedQueueCount` at `:476` and `:520` when a queue returns no pull result or
throws, then keeps collecting the rest (only an all-queues failure throws).
* Contrast the export paths, which do surface them: `exportMessages` at
`:396-408` and `exportExcel` at `:369-393` build
`DLQExportResultVO`/`DLQExcelExportResultVO` with `truncated`,
`failedQueueCount`, `limit`, and `DLQController` returns them as
`X-DLQ-Export-Truncated` / `-FailedQueues` / `-Limit` response headers
(`DlqExportHeaders`, exposed via `CorsConfig`).
* The web client already renders that warning for exports:
`web/src/pages/instance/dlq.tsx:318` and `:430` (base) show `导出可能不完整:…
个队列无法扫描,导出上限 … 条`.
Trigger: `GET
/api/dlq/%DLQ%group-a/messages?instanceId=…&page=1&pageSize=20` against a group
with more than 5000 dead letters in the window, or one whose queue read fails.
Today the response is `{items, total: 5000, page, size}` and the drawer shows a
full-looking list with `total` as the pager's maximum.
## Root cause
The list path dropped the scan metadata its own scan produces and its
sibling export paths deliberately expose. `total` was then a bounded snapshot
size presented as the queue size, and a partial scan was indistinguishable from
a complete one.
## Fix
* New `DLQMessagePageVO` — `items`, `total`, `page`, `size` plus
`truncated`, `failedQueueCount`, `limit` — mirroring the export VOs.
* `DLQProvider.listMessages`, `DLQProviderStub.listMessages`,
`DLQService.listMessages` and `DLQController.listDLQMessages` now carry it;
`RocketMQDLQProvider.listMessages` fills the flags from the
`DeadLetterScanResult` it already had.
* `MessageQueryDlqToolHandler` reads `items`/`total` from the new VO. The AI
tool's *output contract* is deliberately unchanged — adding a field to a
validated tool schema is a separate contract decision.
* The DLQ drawer shows the same warning its export path shows, when the scan
was truncated or a queue could not be read.
## Scoring (AGENTS.md)
* PRIORITY **64** = impact 22 (silent row loss plus a wrong total on an
operational recovery screen; the operator may conclude a group is clean) +
reach 16 (the DLQ message list endpoint and the AI `rmq.dlq.query` tool both
read it) + reproducibility 16 (deterministic: a queue stubbed to fail
reproduces it) + maintenance value 10.
* FIX_CONFIDENCE **72** — the direction is clear and mirrors the export
path, but the response shape is an API decision; a reviewer could prefer a
nested page or new headers, which is why this is below 80.
## Tests
* `RocketMQDLQProviderTest.listMessagesReportsTheQueuesItCouldNotReadTest` —
two queues, one unreadable; asserts one message, `failedQueueCount = 1`,
`truncated = false`, `limit = 5000`.
* `DLQPage.test.tsx` › `warns that the dead-letter list is incomplete when
the scan was not` — `truncated: true, failedQueueCount: 2`; asserts the drawer
warning.
Pre-fix evidence is a probe, because the fix changes a return type so the
typed regression test cannot compile against the old code. The probe calls
`provider.listMessages` with one of two queues failing and asserts the
serialised payload has the flags:
```
# with only the production files restored to 1ef5d860, probe kept
DLQListShapeProbeTest.theListPayloadCarriesTheScanFailureCount -- <<<
FAILURE!
org.opentest4j.AssertionFailedError:
Expecting value to be true but was false
(assertThat(json.has("failedQueueCount")).isTrue())
# same probe on the branch
tests="1" errors="0" skipped="0" failures="0"
```
Web, with only `dlq.tsx` restored to `1ef5d860` and the new test kept:
```
FAIL src/pages/instance/__tests__/DLQPage.test.tsx > warns that the
dead-letter list is incomplete when the scan was not
TestingLibraryElementError: Unable to find an element with the text:
死信消息可能不完整.
```
Post-fix, from the branch:
```
mvn -o test
-Dtest='RocketMQDLQProviderTest,DLQControllerTest,DLQServiceTest,MessageQueryDlqToolHandlerTest,AliyunInstanceProviderTest'
RocketMQDLQProviderTest 40/40, DLQControllerTest 24/24, DLQServiceTest
19/19, MessageQueryDlqToolHandlerTest 2/2
npx vitest run src/pages/instance/__tests__/DLQPage.test.tsx → 22/22
npx tsc --noEmit → clean
npx eslint <touched files> → 0 errors (1
pre-existing react-refresh warning at dlq.tsx:82)
```
Full web suite on the branch: see the verification comment.
## Risk
The list response gains three fields; `items`, `total`, `page` and `size`
keep their names and meaning, so existing consumers only need the new type. The
AI tool output is untouched. The list still scans at most 5000 messages — this
change makes that bound visible instead of removing it.
--
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]