diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java index fcd13b4424e1d9e0ce22721c2fcba518d42cd47a..8115feff6d4d49ee1b36aef4c7a9c08092f6ee48 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/ConfigServiceLocator.java @@ -106,11 +106,11 @@ public class ConfigServiceLocator { transaction.setStatus(Transaction.SUCCESS); List services = response.getBody(); if (services == null || services.isEmpty()) { - logConfigServiceToCat("Empty response!"); + logConfigService("Empty response!"); continue; } m_configServices.set(services); - logConfigServicesToCat(services); + logConfigServices(services); return; } catch (Throwable ex) { Tracer.logEvent("ApolloConfigException", ExceptionUtil.getDetailMessage(ex)); @@ -145,13 +145,13 @@ public class ConfigServiceLocator { return domainName + "/services/config?" + MAP_JOINER.join(queryParams); } - private void logConfigServicesToCat(List serviceDtos) { + private void logConfigServices(List serviceDtos) { for (ServiceDTO serviceDto : serviceDtos) { - logConfigServiceToCat(serviceDto.getHomepageUrl()); + logConfigService(serviceDto.getHomepageUrl()); } } - private void logConfigServiceToCat(String serviceUrl) { + private void logConfigService(String serviceUrl) { Tracer.logEvent("Apollo.Config.Services", serviceUrl); } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java index 325ffe1745e2fd186f4d1f0a5ffd4c3a5802fe4b..2263967250de671fd1fb01289b6a4b393d495855 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/internals/RemoteConfigRepository.java @@ -7,6 +7,7 @@ import java.util.Properties; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; @@ -17,6 +18,8 @@ import com.ctrip.framework.apollo.build.ApolloInjector; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.core.dto.ApolloConfig; import com.ctrip.framework.apollo.core.dto.ServiceDTO; +import com.ctrip.framework.apollo.core.schedule.ExponentialSchedulePolicy; +import com.ctrip.framework.apollo.core.schedule.SchedulePolicy; import com.ctrip.framework.apollo.core.utils.ApolloThreadFactory; import com.ctrip.framework.apollo.exceptions.ApolloConfigException; import com.ctrip.framework.apollo.exceptions.ApolloConfigStatusCodeException; @@ -51,6 +54,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository { private final static ScheduledExecutorService m_executorService; private AtomicReference m_longPollServiceDto; private RateLimiter m_loadConfigRateLimiter; + private AtomicBoolean m_configNeedForceRefresh; + private SchedulePolicy m_loadConfigFailSchedulePolicy; private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper(); private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper(); @@ -73,6 +78,9 @@ public class RemoteConfigRepository extends AbstractConfigRepository { remoteConfigLongPollService = ApolloInjector.getInstance(RemoteConfigLongPollService.class); m_longPollServiceDto = new AtomicReference<>(); m_loadConfigRateLimiter = RateLimiter.create(m_configUtil.getLoadConfigQPS()); + m_configNeedForceRefresh = new AtomicBoolean(true); + m_loadConfigFailSchedulePolicy = new ExponentialSchedulePolicy(m_configUtil.getOnErrorRetryInterval(), + m_configUtil.getOnErrorRetryInterval() * 8); this.trySync(); this.schedulePeriodicRefresh(); this.scheduleLongPollingRefresh(); @@ -154,7 +162,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository { String cluster = m_configUtil.getCluster(); String dataCenter = m_configUtil.getDataCenter(); Tracer.logEvent("Apollo.Client.ConfigMeta", STRING_JOINER.join(appId, cluster, m_namespace)); - int maxRetries = 2; + int maxRetries = m_configNeedForceRefresh.get() ? 2 : 1; + long onErrorSleepTime = 0; // 0 means no sleep Throwable exception = null; List configServices = getConfigServices(); @@ -167,6 +176,18 @@ public class RemoteConfigRepository extends AbstractConfigRepository { } for (ServiceDTO configService : randomConfigServices) { + if (onErrorSleepTime > 0) { + logger.warn( + "Load config failed, will retry in {} {}. appId: {}, cluster: {}, namespaces: {}", + onErrorSleepTime, m_configUtil.getOnErrorRetryIntervalTimeUnit(), appId, cluster, m_namespace); + + try { + m_configUtil.getOnErrorRetryIntervalTimeUnit().sleep(onErrorSleepTime); + } catch (InterruptedException e) { + //ignore + } + } + String url = assembleQueryConfigUrl(configService.getHomepageUrl(), appId, cluster, m_namespace, dataCenter, m_configCache.get()); @@ -179,6 +200,8 @@ public class RemoteConfigRepository extends AbstractConfigRepository { try { HttpResponse response = m_httpUtil.doGet(request, ApolloConfig.class); + m_configNeedForceRefresh.set(false); + m_loadConfigFailSchedulePolicy.success(); transaction.addData("StatusCode", response.getStatusCode()); transaction.setStatus(Transaction.SUCCESS); @@ -215,13 +238,11 @@ public class RemoteConfigRepository extends AbstractConfigRepository { transaction.complete(); } + // if force refresh, do normal sleep, if normal config load, do exponential sleep + onErrorSleepTime = m_configNeedForceRefresh.get() ? m_configUtil.getOnErrorRetryInterval() : + m_loadConfigFailSchedulePolicy.fail(); } - try { - m_configUtil.getOnErrorRetryIntervalTimeUnit().sleep(m_configUtil.getOnErrorRetryInterval()); - } catch (InterruptedException ex) { - //ignore - } } String message = String.format( "Load Apollo Config failed - appId: %s, cluster: %s, namespace: %s", @@ -271,6 +292,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository { m_executorService.submit(new Runnable() { @Override public void run() { + m_configNeedForceRefresh.set(true); trySync(); } }); diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java index 7594bfe5c663d8cce2c9c1c74b99db695d21b2de..d544cff9de1aaf1b7392cf91d802dbece3870f65 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java @@ -1,7 +1,11 @@ package com.ctrip.framework.apollo.spring.config; -import java.util.Collection; -import java.util.Iterator; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Multimap; + +import com.ctrip.framework.apollo.Config; +import com.ctrip.framework.apollo.ConfigService; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -13,14 +17,16 @@ import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; -import com.ctrip.framework.apollo.Config; -import com.ctrip.framework.apollo.ConfigService; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.Iterator; /** - * Apollo Property Sources processor for Spring Annotation Based Application + * Apollo Property Sources processor for Spring Annotation Based Application.

+ * + * The reason why PropertySourcesProcessor implements {@link BeanFactoryPostProcessor} instead of + * {@link org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor} is that lower versions of + * Spring (e.g. 3.1.1) doesn't support registering BeanDefinitionRegistryPostProcessor in ImportBeanDefinitionRegistrar + * - {@link com.ctrip.framework.apollo.spring.annotation.ApolloConfigRegistrar} * * @author Jason Song(song_s@ctrip.com) */ @@ -68,7 +74,7 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir } //only for test - private static void reset() { + private static void reset() { NAMESPACE_NAMES.clear(); } diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java index 9104ea174402e962677c2cbdea90e12a7899fbb6..e09aa12e28f47d5946919ac8263bdb28583be620 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/controller/NotificationController.java @@ -107,17 +107,17 @@ public class NotificationController implements ReleaseMessageListener { } deferredResult - .onTimeout(() -> logWatchedKeysToCat(watchedKeys, "Apollo.LongPoll.TimeOutKeys")); + .onTimeout(() -> logWatchedKeys(watchedKeys, "Apollo.LongPoll.TimeOutKeys")); deferredResult.onCompletion(() -> { //unregister all keys for (String key : watchedKeys) { deferredResults.remove(key, deferredResult); } - logWatchedKeysToCat(watchedKeys, "Apollo.LongPoll.CompletedKeys"); + logWatchedKeys(watchedKeys, "Apollo.LongPoll.CompletedKeys"); }); - logWatchedKeysToCat(watchedKeys, "Apollo.LongPoll.RegisteredKeys"); + logWatchedKeys(watchedKeys, "Apollo.LongPoll.RegisteredKeys"); logger.debug("Listening {} from appId: {}, cluster: {}, namespace: {}, datacenter: {}", watchedKeys, appId, cluster, namespace, dataCenter); } @@ -159,7 +159,7 @@ public class NotificationController implements ReleaseMessageListener { logger.debug("Notification completed"); } - private void logWatchedKeysToCat(Set watchedKeys, String eventName) { + private void logWatchedKeys(Set watchedKeys, String eventName) { for (String watchedKey : watchedKeys) { Tracer.logEvent(eventName, watchedKey); }