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 efcfcc41b fix(instance): evict the data source cache after instance 
deletion (#4202)
efcfcc41b is described below

commit efcfcc41b862842e9e16e9b9c81aa8022b5e387c
Author: halaxy <[email protected]>
AuthorDate: Wed Sep 16 15:59:43 2026 +0800

    fix(instance): evict the data source cache after instance deletion (#4202)
    
    Signed-off-by: halaxy <[email protected]>
---
 .../rocketmq/studio/instance/InstanceService.java       | 17 +++++++++++++++--
 .../rocketmq/studio/settings/SettingsService.java       | 12 +++++++-----
 .../rocketmq/studio/instance/InstanceServiceTest.java   | 16 +++++++++++++++-
 3 files changed, 37 insertions(+), 8 deletions(-)

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 07178719b..e916d35dd 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
@@ -36,10 +36,13 @@ import org.apache.rocketmq.studio.provider.InstanceProvider;
 import org.apache.rocketmq.studio.provider.InstanceProviderRegistry;
 import org.apache.rocketmq.studio.settings.DataSourceVO;
 import org.apache.rocketmq.studio.settings.SettingsRepository;
+import org.apache.rocketmq.studio.settings.SettingsService;
 import jakarta.annotation.PreDestroy;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.dao.DataIntegrityViolationException;
 import org.springframework.stereotype.Service;
@@ -70,6 +73,7 @@ public class InstanceService {
     private final MqClientPool clientPool;
     private final OperationAuditService operationAuditService;
     private final SettingsRepository settingsRepository;
+    private final CacheManager cacheManager;
     private final RegionNames regionNames;
 
     // @Lazy self-injection: Spring AOP proxies intercept @Transactional calls 
only when they
@@ -639,22 +643,31 @@ public class InstanceService {
         removeDataSourceBindings(existing.getName());
         recordAudit("DELETE_INSTANCE", "INSTANCE", String.valueOf(id), null,
                 instanceAuditDetail(existing));
-        releaseApacheEndpointAfterCommit(existing);
+        completeInstanceDeletionAfterCommit(existing);
     }
 
-    private void releaseApacheEndpointAfterCommit(InstanceVO existing) {
+    private void completeInstanceDeletionAfterCommit(InstanceVO existing) {
         if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+            evictDataSourceCache();
             releaseApacheEndpointIfUnused(existing, null);
             return;
         }
         TransactionSynchronizationManager.registerSynchronization(new 
TransactionSynchronization() {
             @Override
             public void afterCommit() {
+                evictDataSourceCache();
                 releaseApacheEndpointIfUnused(existing, null);
             }
         });
     }
 
+    private void evictDataSourceCache() {
+        Cache cache = cacheManager.getCache(SettingsService.DATA_SOURCE_CACHE);
+        if (cache != null) {
+            cache.clear();
+        }
+    }
+
     /**
      * Deletes the selected instances one by one, collecting per-instance 
failures (for example
      * an APACHE instance that still owns topics/groups) instead of aborting 
the whole batch.
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
index 7a1d2da59..1d616969e 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsService.java
@@ -56,6 +56,8 @@ import java.util.Set;
 @Service
 public class SettingsService {
 
+    public static final String DATA_SOURCE_CACHE = "data-sources";
+
     private static final String REDACTED_NOTIFICATION_WEBHOOK = "******";
     private static final List<byte[]> CLOUD_METADATA_ADDRESSES = List.of(
             new byte[] {
@@ -212,13 +214,13 @@ public class SettingsService {
     // every time the datasource dropdown re-fetches. Caching it with the
     // write paths evicted below keeps the user-visible list correct while
     // removing a per-tab DB round trip.
-    @Cacheable("data-sources")
+    @Cacheable(DATA_SOURCE_CACHE)
     public List<DataSourceVO> listDataSources() {
         log.debug("Listing all data sources");
         return settingsRepository.findAllDataSources();
     }
 
-    @Cacheable("data-sources")
+    @Cacheable(DATA_SOURCE_CACHE)
     public PageResult<DataSourceVO> listDataSources(String search, String 
type, int page, int pageSize) {
         if (page < 1) {
             throw new BusinessException(400, "page must be greater than zero");
@@ -232,7 +234,7 @@ public class SettingsService {
     }
 
 
-    @CacheEvict(value = "data-sources", allEntries = true)
+    @CacheEvict(value = DATA_SOURCE_CACHE, allEntries = true)
     public DataSourceVO createDataSource(DataSourceVO dataSource) {
         if (dataSource == null) {
             throw new BusinessException(400, "Data source request is 
required");
@@ -245,7 +247,7 @@ public class SettingsService {
     }
 
 
-    @CacheEvict(value = "data-sources", allEntries = true)
+    @CacheEvict(value = DATA_SOURCE_CACHE, allEntries = true)
     public DataSourceVO updateDataSource(DataSourceVO dataSource) {
         if (dataSource == null) {
             throw new BusinessException(400, "Data source request is 
required");
@@ -270,7 +272,7 @@ public class SettingsService {
     }
 
 
-    @CacheEvict(value = "data-sources", allEntries = true)
+    @CacheEvict(value = DATA_SOURCE_CACHE, allEntries = true)
     public void deleteDataSource(String key) {
         String normalizedKey = normalizeDataSourceKey(key);
         log.info("Deleting data source: {}", normalizedKey);
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 a41102eab..4d41e3911 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
@@ -34,6 +34,9 @@ import 
org.apache.rocketmq.studio.provider.InstanceProviderRegistry;
 import org.apache.rocketmq.studio.provider.InstanceProvider;
 import org.apache.rocketmq.studio.settings.DataSourceVO;
 import org.apache.rocketmq.studio.settings.SettingsRepository;
+import org.apache.rocketmq.studio.settings.SettingsService;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
 import org.springframework.transaction.support.TransactionSynchronization;
 import 
org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.junit.jupiter.api.Test;
@@ -94,6 +97,12 @@ class InstanceServiceTest {
     @Mock
     private SettingsRepository settingsRepository;
 
+    @Mock
+    private CacheManager cacheManager;
+
+    @Mock
+    private Cache dataSourceCache;
+
     @Mock
     private RegionNames regionNames;
 
@@ -1006,7 +1015,7 @@ class InstanceServiceTest {
     }
 
     @Test
-    void deleteInstanceShouldDeferEndpointReleaseUntilAfterCommitTest() {
+    void deleteInstanceShouldDeferCleanupUntilAfterCommitTest() {
         InstanceVO existing = InstanceVO.builder()
                 .name("to-delete")
                 .endpoint("namesrv:9876")
@@ -1016,6 +1025,7 @@ class InstanceServiceTest {
         when(instanceRepository.findAll()).thenReturn(List.of());
         
when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
         when(instanceRepository.deleteById(1L)).thenReturn(true);
+        
when(cacheManager.getCache(SettingsService.DATA_SOURCE_CACHE)).thenReturn(dataSourceCache);
 
         TransactionSynchronizationManager.initSynchronization();
         try {
@@ -1023,6 +1033,7 @@ class InstanceServiceTest {
 
             verify(adminFactory, never()).release(any());
             verify(clientPool, never()).release(any());
+            verify(dataSourceCache, never()).clear();
 
             for (TransactionSynchronization sync : 
TransactionSynchronizationManager.getSynchronizations()) {
                 sync.afterCommit();
@@ -1033,6 +1044,7 @@ class InstanceServiceTest {
 
         verify(adminFactory).release("namesrv:9876");
         verify(clientPool).release("namesrv:9876");
+        verify(dataSourceCache).clear();
     }
 
     @Test
@@ -1048,11 +1060,13 @@ class InstanceServiceTest {
         when(instanceRepository.deleteById(1L)).thenReturn(true);
         
when(settingsRepository.findAllDataSources()).thenReturn(List.of(dataSource));
         
when(settingsRepository.replaceDataSource(dataSource)).thenReturn(true);
+        
when(cacheManager.getCache(SettingsService.DATA_SOURCE_CACHE)).thenReturn(dataSourceCache);
 
         instanceService.deleteInstance(1L);
 
         assertThat(dataSource.getInstanceIds()).containsExactly("inst-2");
         verify(settingsRepository).replaceDataSource(dataSource);
+        verify(dataSourceCache).clear();
     }
 
     @Test

Reply via email to