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

Reply via email to