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 e30c83e24 fix: continue batch instance deletion after runtime failures
(#2660)
e30c83e24 is described below
commit e30c83e242feb85062ac829e208dce639d52604a
Author: xdz997 <[email protected]>
AuthorDate: Wed Sep 2 19:47:05 2026 +0800
fix: continue batch instance deletion after runtime failures (#2660)
---
.../rocketmq/studio/instance/InstanceService.java | 15 ++++++++
.../studio/instance/InstanceServiceTest.java | 44 ++++++++++++++++++++++
2 files changed, 59 insertions(+)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
index dc64a5885..935f91dbb 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
@@ -71,6 +71,7 @@ public class InstanceService {
static final int COUNT_PARALLELISM = 8;
static final long COUNT_TIMEOUT_SECONDS = 3;
+ private static final int MAX_BATCH_FAILURE_MESSAGE_LENGTH = 500;
private final ExecutorService countExecutor =
Executors.newFixedThreadPool(COUNT_PARALLELISM, runnable -> {
Thread thread = new Thread(runnable, "instance-resource-counts");
@@ -509,11 +510,25 @@ public class InstanceService {
deleted++;
} catch (BusinessException ex) {
failed.add(instanceId + ": " + ex.getMessage());
+ } catch (RuntimeException ex) {
+ String message = batchFailureMessage(ex);
+ log.warn("Failed to delete instance {} during batch operation:
{}", instanceId, message);
+ failed.add(instanceId + ": " + message);
}
}
return
BatchDeleteResultVO.builder().deleted(deleted).failed(failed).build();
}
+ private static String batchFailureMessage(RuntimeException failure) {
+ String message = failure.getMessage();
+ if (!StringUtils.hasText(message)) {
+ message = failure.getClass().getSimpleName();
+ }
+ message = message.trim();
+ return message.length() > MAX_BATCH_FAILURE_MESSAGE_LENGTH
+ ? message.substring(0, MAX_BATCH_FAILURE_MESSAGE_LENGTH) :
message;
+ }
+
private void removeDataSourceBindings(String instanceId) {
for (DataSourceVO dataSource :
settingsRepository.findAllDataSources()) {
List<String> instanceIds = dataSource.getInstanceIds();
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
index b4d03a14a..4f77d9222 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
@@ -782,6 +782,50 @@ class InstanceServiceTest {
assertThat(result.getFailed()).containsExactly("missing: Instance not
found: missing");
}
+ @Test
+ void deleteInstancesShouldContinueAfterProviderRuntimeFailureTest() {
+ InstanceVO failedInstance =
InstanceVO.builder().name("inst-a").build();
+ failedInstance.setId(1L);
+ InstanceVO deletedInstance =
InstanceVO.builder().name("inst-b").build();
+ deletedInstance.setId(2L);
+
when(instanceRepository.findByIdentifier("inst-a")).thenReturn(Optional.of(failedInstance));
+
when(instanceRepository.findByIdentifier("inst-b")).thenReturn(Optional.of(deletedInstance));
+
when(instanceRepository.findById(1L)).thenReturn(Optional.of(failedInstance));
+
when(instanceRepository.findById(2L)).thenReturn(Optional.of(deletedInstance));
+
when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
+ when(instanceProvider.countTopics("1")).thenThrow(new
IllegalStateException("broker unavailable"));
+ when(instanceProvider.countTopics("2")).thenReturn(0);
+ when(instanceProvider.countGroups("2")).thenReturn(0);
+ when(instanceRepository.deleteById(2L)).thenReturn(true);
+
+ BatchDeleteResultVO result =
instanceService.deleteInstances(List.of("inst-a", "inst-b"));
+
+ assertThat(result.getDeleted()).isEqualTo(1);
+ assertThat(result.getFailed()).containsExactly("inst-a: broker
unavailable");
+ verify(instanceProvider).countTopics("1");
+ verify(instanceRepository).findByIdentifier("inst-b");
+ verify(instanceProvider).countTopics("2");
+ verify(instanceProvider).countGroups("2");
+ verify(instanceRepository).deleteById(2L);
+ }
+
+ @Test
+ void deleteInstancesShouldBoundUnexpectedFailureMessagesTest() {
+ InstanceVO existing = InstanceVO.builder().name("inst-a").build();
+ existing.setId(1L);
+ String oversizedMessage = "x".repeat(600);
+
when(instanceRepository.findByIdentifier("inst-a")).thenReturn(Optional.of(existing));
+
when(instanceRepository.findById(1L)).thenReturn(Optional.of(existing));
+
when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
+ when(instanceProvider.countTopics("1")).thenThrow(new
IllegalStateException(oversizedMessage));
+
+ BatchDeleteResultVO result =
instanceService.deleteInstances(List.of("inst-a"));
+
+ assertThat(result.getDeleted()).isZero();
+ assertThat(result.getFailed()).singleElement()
+ .isEqualTo("inst-a: " + "x".repeat(500));
+ }
+
@Test
void deleteInstancesShouldRejectEmptySelectionTest() {
assertThatThrownBy(() -> instanceService.deleteInstances(List.of()))