Skip to content

Commit 34b85d8

Browse files
committed
feat:support config empty protection.
1 parent 3aa56a3 commit 34b85d8

File tree

4 files changed

+144
-17
lines changed

4 files changed

+144
-17
lines changed

polaris-common/polaris-config/src/main/java/com/tencent/polaris/api/config/configuration/ConnectorConfig.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,18 @@ public interface ConnectorConfig extends ServerConnectorConfig {
3333
* @return 连接器类型
3434
*/
3535
String getConnectorType();
36+
37+
/**
38+
* 是否开启推空保护
39+
*
40+
* @return 是否开启推空保护
41+
*/
42+
Boolean isEmptyProtectionEnable();
43+
44+
/**
45+
* 推空保护过期时间,单位毫秒
46+
*
47+
* @return 推空保护过期时间
48+
*/
49+
Long getEmptyProtectionExpiredInterval();
3650
}

polaris-common/polaris-config/src/main/java/com/tencent/polaris/factory/config/configuration/ConnectorConfigImpl.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ public class ConnectorConfigImpl extends ServerConnectorConfigImpl implements Co
6161
@JsonProperty
6262
private Integer configFileGroupThreadNum = 10;
6363

64+
@JsonProperty
65+
private Boolean emptyProtectionEnable = true;
66+
67+
@JsonProperty
68+
@JsonDeserialize(using = TimeStrJsonDeserializer.class)
69+
private Long emptyProtectionExpiredInterval = 7 * 24 * 3600 * 1000L;
70+
6471
@Override
6572
public void verify() {
6673
ConfigUtils.validateString(connectorType, "configConnectorType");
@@ -91,6 +98,12 @@ public void setDefault(Object defaultObject) {
9198
if (connectorType == null) {
9299
this.connectorType = connectorConfig.getConnectorType();
93100
}
101+
if (emptyProtectionEnable == null) {
102+
this.emptyProtectionEnable = connectorConfig.isEmptyProtectionEnable();
103+
}
104+
if (emptyProtectionExpiredInterval == null) {
105+
this.emptyProtectionExpiredInterval = connectorConfig.getEmptyProtectionExpiredInterval();
106+
}
94107
}
95108
}
96109

@@ -159,4 +172,21 @@ public void setConfigFileGroupThreadNum(Integer configFileGroupThreadNum) {
159172
this.configFileGroupThreadNum = configFileGroupThreadNum;
160173
}
161174

175+
@Override
176+
public Boolean isEmptyProtectionEnable() {
177+
return emptyProtectionEnable;
178+
}
179+
180+
public void setEmptyProtectionEnable(Boolean emptyProtectionEnable) {
181+
this.emptyProtectionEnable = emptyProtectionEnable;
182+
}
183+
184+
@Override
185+
public Long getEmptyProtectionExpiredInterval() {
186+
return emptyProtectionExpiredInterval;
187+
}
188+
189+
public void setEmptyProtectionExpiredInterval(Long emptyProtectionExpiredInterval) {
190+
this.emptyProtectionExpiredInterval = emptyProtectionExpiredInterval;
191+
}
162192
}

polaris-configuration/polaris-configuration-client/src/main/java/com/tencent/polaris/configuration/client/internal/RemoteConfigFileRepo.java

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,9 @@
2727
import com.tencent.polaris.client.api.SDKContext;
2828
import com.tencent.polaris.client.util.NamedThreadFactory;
2929
import com.tencent.polaris.configuration.api.core.ConfigFileMetadata;
30+
import com.tencent.polaris.configuration.client.util.ConfigFileUtils;
3031

31-
import java.util.concurrent.ExecutorService;
32-
import java.util.concurrent.Executors;
33-
import java.util.concurrent.ScheduledExecutorService;
34-
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.*;
3533
import java.util.concurrent.atomic.AtomicLong;
3634
import java.util.concurrent.atomic.AtomicReference;
3735

@@ -58,6 +56,17 @@ public class RemoteConfigFileRepo extends AbstractConfigFileRepo {
5856

5957
private String token;
6058

59+
private final boolean emptyProtection;
60+
61+
private final long emptyProtectionExpiredInterval;
62+
63+
/**
64+
* 淘汰线程
65+
*/
66+
private final ScheduledExecutorService emptyProtectionExpireExecutor;
67+
68+
private ScheduledFuture<?> emptyProtectionExpireFuture;
69+
6170
static {
6271
createPullExecutorService();
6372
}
@@ -80,6 +89,9 @@ public RemoteConfigFileRepo(SDKContext sdkContext,
8089
//获取远程调用插件实现类
8190
this.configFileConnector = connector;
8291
this.fallbackToLocalCache = sdkContext.getConfig().getConfigFile().getServerConnector().getFallbackToLocalCache();
92+
this.emptyProtection = sdkContext.getConfig().getConfigFile().getServerConnector().isEmptyProtectionEnable();
93+
this.emptyProtectionExpiredInterval = sdkContext.getConfig().getConfigFile().getServerConnector().getEmptyProtectionExpiredInterval();
94+
this.emptyProtectionExpireExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("polaris-config-empty-protection"));
8395
//注册 destroy hook
8496
registerRepoDestroyHook(sdkContext);
8597
//同步从远程仓库拉取一次
@@ -163,32 +175,48 @@ protected void doPull() {
163175
} else {
164176
shouldUpdateLocalCache = remoteConfigFile.get() == null || pulledConfigFile.getVersion() != remoteConfigFile.get().getVersion();
165177
}
166-
if (shouldUpdateLocalCache) {
178+
// 构造更新回调动作
179+
Runnable runnable = () -> {
167180
ConfigFile copiedConfigFile = deepCloneConfigFile(pulledConfigFile);
168181
remoteConfigFile.set(copiedConfigFile);
169182
//配置有更新,触发回调
170183
fireChangeEvent(copiedConfigFile);
171184

172185
// update local file cache
173186
this.configFilePersistHandler.asyncSaveConfigFile(pulledConfigFile);
187+
};
188+
if (shouldUpdateLocalCache && checkEmptyProtect(response)) {
189+
shouldUpdateLocalCache = false;
190+
submitEmptyProtectionExpireTask(runnable);
191+
}
192+
if (shouldUpdateLocalCache) {
193+
runnable.run();
174194
}
175195
return;
176196
}
177197

178198
//远端没有此配置文件
179199
if (response.getCode() == ServerCodes.NOT_FOUND_RESOURCE) {
180-
LOGGER.warn("[Config] config file not found, please check whether config file released. {}",
181-
configFileMetadata);
182-
//delete local file cache
183-
this.configFilePersistHandler
184-
.asyncDeleteConfigFile(new ConfigFile(configFileMetadata.getNamespace(),
185-
configFileMetadata.getFileGroup(), configFileMetadata.getFileName()));
186-
187-
//删除配置文件
188-
if (remoteConfigFile.get() != null) {
189-
remoteConfigFile.set(null);
190-
//删除配置文件也需要触发通知
191-
fireChangeEvent(null);
200+
// 构造更新回调动作
201+
Runnable runnable = () -> {
202+
//delete local file cache
203+
this.configFilePersistHandler
204+
.asyncDeleteConfigFile(new ConfigFile(configFileMetadata.getNamespace(),
205+
configFileMetadata.getFileGroup(), configFileMetadata.getFileName()));
206+
207+
//删除配置文件
208+
if (remoteConfigFile.get() != null) {
209+
remoteConfigFile.set(null);
210+
//删除配置文件也需要触发通知
211+
fireChangeEvent(null);
212+
}
213+
};
214+
if (checkEmptyProtect(response)) {
215+
submitEmptyProtectionExpireTask(runnable);
216+
} else {
217+
LOGGER.warn("[Config] config file not found, please check whether config file released. {}",
218+
configFileMetadata);
219+
runnable.run();
192220
}
193221
return;
194222
}
@@ -293,4 +321,31 @@ protected void doDestroy() {
293321
static void destroyPullExecutor() {
294322
ThreadPoolUtils.waitAndStopThreadPools(new ExecutorService[]{pullExecutorService});
295323
}
324+
325+
/**
326+
* 若配置为空,则推空保护开启,则不刷新配置
327+
*
328+
* @param configFileResponse
329+
* @return
330+
*/
331+
private boolean checkEmptyProtect(ConfigFileResponse configFileResponse) {
332+
if (emptyProtection && ConfigFileUtils.checkConfigContentEmpty(configFileResponse)) {
333+
LOGGER.warn("Empty response from remote with {}, will not refresh config.", getIdentifier());
334+
return true;
335+
}
336+
return false;
337+
}
338+
339+
private void submitEmptyProtectionExpireTask(Runnable runnable) {
340+
if (emptyProtectionExpireFuture == null || emptyProtectionExpireFuture.isCancelled() || emptyProtectionExpireFuture.isDone()) {
341+
LOGGER.info("Empty protection expire task of {} submit.", getIdentifier());
342+
emptyProtectionExpireFuture = emptyProtectionExpireExecutor.schedule(runnable, emptyProtectionExpiredInterval, TimeUnit.MILLISECONDS);
343+
}
344+
}
345+
346+
private String getIdentifier() {
347+
return configFileMetadata.getNamespace() + "."
348+
+ configFileMetadata.getFileGroup() + "."
349+
+ configFileMetadata.getFileName();
350+
}
296351
}

polaris-configuration/polaris-configuration-client/src/main/java/com/tencent/polaris/configuration/client/util/ConfigFileUtils.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
package com.tencent.polaris.configuration.client.util;
1919

2020
import com.google.common.collect.Maps;
21+
import com.tencent.polaris.api.exception.ServerCodes;
22+
import com.tencent.polaris.api.plugin.configuration.ConfigFile;
23+
import com.tencent.polaris.api.plugin.configuration.ConfigFileResponse;
2124
import com.tencent.polaris.api.utils.StringUtils;
2225
import com.tencent.polaris.configuration.api.core.ConfigFileMetadata;
26+
import com.tencent.polaris.logging.LoggerFactory;
27+
import org.slf4j.Logger;
2328

2429
import java.util.Collections;
2530
import java.util.Map;
@@ -31,6 +36,8 @@
3136
*/
3237
public class ConfigFileUtils {
3338

39+
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigFileUtils.class);
40+
3441
public static void checkConfigFileMetadata(ConfigFileMetadata configFileMetadata) {
3542
if (StringUtils.isBlank(configFileMetadata.getNamespace())) {
3643
throw new IllegalArgumentException("namespace cannot be empty.");
@@ -57,4 +64,25 @@ public static Set<String> stringPropertyNames(Properties properties) {
5764
}
5865
return map.keySet();
5966
}
67+
68+
public static boolean checkConfigContentEmpty(ConfigFileResponse configFileResponse) {
69+
if (configFileResponse == null) {
70+
LOGGER.debug("config file response is null.");
71+
return true;
72+
}
73+
if (configFileResponse.getCode() == ServerCodes.NOT_FOUND_RESOURCE) {
74+
LOGGER.debug("config file not found. maybe not exist or deleted.");
75+
return true;
76+
}
77+
ConfigFile configFile = configFileResponse.getConfigFile();
78+
if (configFile == null) {
79+
LOGGER.debug("config file is null.");
80+
return true;
81+
}
82+
if (StringUtils.isBlank(configFile.getContent())) {
83+
LOGGER.debug("config file content is empty.");
84+
return true;
85+
}
86+
return false;
87+
}
6088
}

0 commit comments

Comments
 (0)