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