This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new fb821990 feat: resolve message trace by instance endpoint (#1082)
fb821990 is described below
commit fb8219901f2c9862b114e87b9634baf447cf6dab
Author: aias00 <[email protected]>
AuthorDate: Thu Aug 6 01:25:21 2026 -0700
feat: resolve message trace by instance endpoint (#1082)
---
.../studio/instance/message/MessageController.java | 4 ++--
.../studio/instance/message/MessageProvider.java | 2 +-
.../studio/instance/message/MessageProviderStub.java | 2 +-
.../studio/instance/message/MessageService.java | 4 ++--
.../studio/rocketmq/RocketMQMessageProvider.java | 19 +++++++++++--------
.../instance/message/MessageControllerTest.java | 12 ++++++++++++
.../instance/message/MessageProviderStubTest.java | 2 +-
.../studio/rocketmq/RocketMQMessageProviderTest.java | 4 ++--
web/src/api/message.test.ts | 12 ++++++++----
web/src/api/message.ts | 3 ++-
web/src/pages/instance/message.tsx | 2 +-
web/src/services/messageService.ts | 7 +++++--
12 files changed, 48 insertions(+), 25 deletions(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageController.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageController.java
index 6c061a28..3b2ddbfb 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageController.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageController.java
@@ -46,7 +46,7 @@ public class MessageController {
}
@GetMapping("/{msgId}/trace")
- public Result<TraceRecordVO> getMessageTrace(@PathVariable String msgId) {
- return Result.ok(messageService.getMessageTrace(msgId));
+ public Result<TraceRecordVO> getMessageTrace(@PathVariable String msgId,
@RequestParam String instanceId) {
+ return Result.ok(messageService.getMessageTrace(instanceId, msgId));
}
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProvider.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProvider.java
index 744d4677..fe79a31e 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProvider.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProvider.java
@@ -23,5 +23,5 @@ public interface MessageProvider {
List<MessageRecordVO> queryMessages(String instanceId, String topic,
String msgId, String tag, String key, Long startTime,
Long endTime);
- TraceRecordVO getMessageTrace(String msgId);
+ TraceRecordVO getMessageTrace(String instanceId, String msgId);
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProviderStub.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProviderStub.java
index f4352a1d..932d7117 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProviderStub.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageProviderStub.java
@@ -36,7 +36,7 @@ public class MessageProviderStub implements MessageProvider {
}
@Override
- public TraceRecordVO getMessageTrace(String msgId) {
+ public TraceRecordVO getMessageTrace(String instanceId, String msgId) {
log.warn("MessageProviderStub.getMessageTrace called but no real
message provider is configured");
throw unsupported();
}
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageService.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageService.java
index 549ce4f9..58412c06 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageService.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/message/MessageService.java
@@ -39,9 +39,9 @@ public class MessageService {
return messageProvider.queryMessages(instanceId, topic, msgId, tag,
key, startTime, endTime);
}
- public TraceRecordVO getMessageTrace(String msgId) {
+ public TraceRecordVO getMessageTrace(String instanceId, String msgId) {
log.info("Getting message trace: msgId={}", msgId);
- return messageProvider.getMessageTrace(msgId);
+ return messageProvider.getMessageTrace(instanceId, msgId);
}
private void validateTopicQueryWindow(String topic, String msgId, String
key, Long startTime, Long endTime) {
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
index a08b0e81..f23d7b7e 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
@@ -24,8 +24,8 @@ import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageId;
import org.apache.rocketmq.common.message.MessageQueue;
-import org.apache.rocketmq.studio.common.domain.enums.DeliveryStatus;
import org.apache.rocketmq.studio.cluster.broker.RuntimeAdminClientResolver;
+import org.apache.rocketmq.studio.common.domain.enums.DeliveryStatus;
import org.apache.rocketmq.studio.instance.message.ConsumerStatusVO;
import org.apache.rocketmq.studio.instance.message.MessageProvider;
import org.apache.rocketmq.studio.instance.message.MessageRecordVO;
@@ -84,13 +84,16 @@ public class RocketMQMessageProvider implements
MessageProvider {
private final ObjectProvider<DefaultMQAdminExt> adminExtProvider;
private final RuntimeAdminClientResolver runtimeAdminClientResolver;
private final QueryHistoryService queryHistoryService;
+ private final RocketMQProperties properties;
public RocketMQMessageProvider(ObjectProvider<DefaultMQAdminExt>
adminExtProvider,
RuntimeAdminClientResolver
runtimeAdminClientResolver,
- QueryHistoryService queryHistoryService) {
+ QueryHistoryService queryHistoryService,
+ RocketMQProperties properties) {
this.adminExtProvider = adminExtProvider;
this.runtimeAdminClientResolver = runtimeAdminClientResolver;
this.queryHistoryService = queryHistoryService;
+ this.properties = properties;
}
@Override
@@ -239,12 +242,12 @@ public class RocketMQMessageProvider implements
MessageProvider {
}
@Override
- public TraceRecordVO getMessageTrace(String msgId) {
- DefaultMQAdminExt adminExt = adminExtProvider.getIfAvailable();
- if (adminExt == null) {
- log.warn("DefaultMQAdminExt is not configured, returning empty
trace");
- return emptyTrace();
- }
+ public TraceRecordVO getMessageTrace(String instanceId, String msgId) {
+ return runtimeAdminClientResolver.execute(instanceId,
+ adminExt -> getMessageTrace((DefaultMQAdminExt) adminExt,
msgId));
+ }
+
+ private TraceRecordVO getMessageTrace(DefaultMQAdminExt adminExt, String
msgId) {
long now = System.currentTimeMillis();
long begin = now - ONE_HOUR_MILLIS;
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageControllerTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageControllerTest.java
index 1b1ef293..36a87ee5 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageControllerTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageControllerTest.java
@@ -70,4 +70,16 @@ class MessageControllerTest {
verify(messageService).queryMessages(eq("instance-a"), eq("orders"),
isNull(), eq("created"), eq("order-1"),
eq(1784246400000L), eq(1784332800000L));
}
+
+ @Test
+ void messageTraceShouldPassInstanceId() throws Exception {
+ TraceRecordVO trace =
TraceRecordVO.builder().nodes(List.of()).consumerStatus(List.of()).build();
+ when(messageService.getMessageTrace("instance-a",
"msg-001")).thenReturn(trace);
+
+ mockMvc.perform(get("/api/messages/msg-001/trace").param("instanceId",
"instance-a"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value(200));
+
+ verify(messageService).getMessageTrace("instance-a", "msg-001");
+ }
}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageProviderStubTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageProviderStubTest.java
index bb8d4109..be2fa14f 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageProviderStubTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/message/MessageProviderStubTest.java
@@ -37,7 +37,7 @@ class MessageProviderStubTest {
@Test
void getMessageTraceShouldFailExplicitlyWhenRealProviderIsMissing() {
- assertThatThrownBy(() -> provider.getMessageTrace("msg-001"))
+ assertThatThrownBy(() -> provider.getMessageTrace("instance-a",
"msg-001"))
.isInstanceOf(BusinessException.class)
.hasMessage("Message query provider is not configured")
.extracting("code")
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProviderTest.java
b/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProviderTest.java
index 4c8e90c4..bd025e1f 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProviderTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProviderTest.java
@@ -163,7 +163,7 @@ class RocketMQMessageProviderTest {
when(adminExt.queryMessage(anyString(), anyString(), anyInt(),
anyLong(), anyLong()))
.thenReturn(queryResult);
- TraceRecordVO record = provider.getMessageTrace("msg-123");
+ TraceRecordVO record = provider.getMessageTrace("instance-a",
"msg-123");
assertThat(record.getNodes()).hasSize(2);
TraceNodeVO produce = record.getNodes().get(0);
@@ -196,7 +196,7 @@ class RocketMQMessageProviderTest {
when(adminExt.queryMessage(anyString(), anyString(), anyInt(),
anyLong(), anyLong()))
.thenReturn(queryResult);
- TraceRecordVO record = provider.getMessageTrace("msg-tx");
+ TraceRecordVO record = provider.getMessageTrace("instance-a",
"msg-tx");
assertThat(record.getNodes()).hasSize(1);
TraceNodeVO transaction = record.getNodes().get(0);
diff --git a/web/src/api/message.test.ts b/web/src/api/message.test.ts
index 32107a02..38802c4d 100644
--- a/web/src/api/message.test.ts
+++ b/web/src/api/message.test.ts
@@ -107,9 +107,11 @@ describe('message API', () => {
},
],
};
- mock.onGet('/messages/msg-1/trace').reply(200, { code: 200, data: trace });
+ mock
+ .onGet('/messages/msg-1/trace', { params: { instanceId: 'instance-a' } })
+ .reply(200, { code: 200, data: trace });
- await expect(getMessageTrace('msg-1')).resolves.toEqual(trace);
+ await expect(getMessageTrace('msg-1',
'instance-a')).resolves.toEqual(trace);
});
it('encodes message IDs before requesting trace records', async () => {
@@ -117,8 +119,10 @@ describe('message API', () => {
nodes: [],
consumerStatus: [],
};
- mock.onGet('/messages/AC1E0A64%2F0000%202A9F%3A1/trace').reply(200, {
code: 200, data: trace });
+ mock
+ .onGet('/messages/AC1E0A64%2F0000%202A9F%3A1/trace', { params: {
instanceId: 'instance-a' } })
+ .reply(200, { code: 200, data: trace });
- await expect(getMessageTrace('AC1E0A64/0000
2A9F:1')).resolves.toEqual(trace);
+ await expect(getMessageTrace('AC1E0A64/0000 2A9F:1',
'instance-a')).resolves.toEqual(trace);
});
});
diff --git a/web/src/api/message.ts b/web/src/api/message.ts
index 57c17138..8847b157 100644
--- a/web/src/api/message.ts
+++ b/web/src/api/message.ts
@@ -77,9 +77,10 @@ export async function queryMessages(params: MessageQuery) {
return sortMessagesByStoreTimeDesc(res.data.data);
}
-export async function getMessageTrace(msgId: string) {
+export async function getMessageTrace(msgId: string, instanceId?: string) {
const res = await client.get<{ data: TraceRecord }>(
`/messages/${encodeURIComponent(msgId)}/trace`,
+ { params: { instanceId } },
);
return res.data.data;
}
diff --git a/web/src/pages/instance/message.tsx
b/web/src/pages/instance/message.tsx
index e7a59a6b..96bf564c 100644
--- a/web/src/pages/instance/message.tsx
+++ b/web/src/pages/instance/message.tsx
@@ -391,7 +391,7 @@ const MessagePage = () => {
setTraceLoading(true);
setTraceError(null);
try {
- const result = await getMessageTrace(record.msgId);
+ const result = await getMessageTrace(record.msgId, selectedInstanceId);
if (traceGenerationRef.current !== requestGeneration) return;
setTraceData(result);
setTraceError(null);
diff --git a/web/src/services/messageService.ts
b/web/src/services/messageService.ts
index 31ccf040..9e08e612 100644
--- a/web/src/services/messageService.ts
+++ b/web/src/services/messageService.ts
@@ -48,12 +48,15 @@ export async function queryMessages(params: MessageQuery):
Promise<MessageRecord
return messageApi.queryMessages(params);
}
-export async function getMessageTrace(msgId: string): Promise<TraceRecord |
null> {
+export async function getMessageTrace(
+ msgId: string,
+ instanceId?: string,
+): Promise<TraceRecord | null> {
if (isMockMode()) {
const trace = mockMessageTraces[msgId] as unknown as TraceRecord |
undefined;
return trace ? cloneTrace(trace) : null;
}
- return messageApi.getMessageTrace(msgId);
+ return messageApi.getMessageTrace(msgId, instanceId);
}
export async function listDLQGroups(instanceId: string): Promise<DLQGroup[]> {