Fix the problem of fetching old value from plugin setting fetcher (#6216)

#### What type of PR is this?

/kind bug
/area core
/area plugin
/milestone 2.17.x

#### What this PR does / why we need it:

This PR  makes sure the method `cache#put` is called before the event is published to avoid the event listener to fetch the old value from the cache.

The problem was introduced by <https://github.com/halo-dev/halo/pull/6141>.

#### Which issue(s) this PR fixes:

Fixes #6213 

#### Does this PR introduce a user-facing change?

```release-note
修复在插件配置变更监听器中始终获取到旧数据的问题
```
pull/6220/head v2.17.0-beta.1
John Niang 2024-06-30 10:57:11 +08:00 committed by GitHub
parent 8e97814018
commit 9410006659
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 13 additions and 4 deletions

View File

@ -162,13 +162,13 @@ public class DefaultReactiveSettingFetcher
if (configMapData != null) { if (configMapData != null) {
configMapData.forEach((key, value) -> result.put(key, readTree(value))); configMapData.forEach((key, value) -> result.put(key, readTree(value)));
} }
// update cache
cache.put(pluginName, result);
applicationContext.publishEvent(PluginConfigUpdatedEvent.builder() applicationContext.publishEvent(PluginConfigUpdatedEvent.builder()
.source(this) .source(this)
.oldConfig(existData) .oldConfig(existData)
.newConfig(result) .newConfig(result)
.build()); .build());
// update cache
cache.put(pluginName, result);
}); });
return Result.doNotRetry(); return Result.doNotRetry();
} }

View File

@ -3,6 +3,8 @@ package run.halo.app.plugin;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -18,6 +20,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
@ -64,7 +67,8 @@ class DefaultSettingFetcherTest {
private DefaultReactiveSettingFetcher reactiveSettingFetcher; private DefaultReactiveSettingFetcher reactiveSettingFetcher;
private DefaultSettingFetcher settingFetcher; private DefaultSettingFetcher settingFetcher;
private final Cache cache = new ConcurrentMapCache(buildCacheKey(pluginContext.getName())); @Spy
Cache cache = new ConcurrentMapCache(buildCacheKey(pluginContext.getName()));
@BeforeEach @BeforeEach
void setUp() { void setUp() {
@ -115,7 +119,12 @@ class DefaultSettingFetcherTest {
when(blockingClient.fetch(eq(ConfigMap.class), eq(pluginContext.getConfigMapName()))) when(blockingClient.fetch(eq(ConfigMap.class), eq(pluginContext.getConfigMapName())))
.thenReturn(Optional.of(configMap)); .thenReturn(Optional.of(configMap));
reactiveSettingFetcher.reconcile(new Reconciler.Request(pluginContext.getConfigMapName())); reactiveSettingFetcher.reconcile(new Reconciler.Request(pluginContext.getConfigMapName()));
verify(applicationContext).publishEvent(any());
// Make sure the method cache#put is called before the event is published
// to avoid the event listener to fetch the old value from the cache
var inOrder = inOrder(cache, applicationContext);
inOrder.verify(cache).put(eq("fake"), any());
inOrder.verify(applicationContext).publishEvent(isA(PluginConfigUpdatedEvent.class));
Map<String, JsonNode> updatedValues = settingFetcher.getValues(); Map<String, JsonNode> updatedValues = settingFetcher.getValues();
verify(client, times(1)).fetch(eq(ConfigMap.class), any()); verify(client, times(1)).fetch(eq(ConfigMap.class), any());