Commit 501aba1b by Jason Song

Merge pull request #204 from nobodyiam/long-polling-server-stick

Long polling server stick
parents 33ec16d3 71128118
package com.ctrip.apollo.internals;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.google.gson.reflect.TypeToken;
import com.ctrip.apollo.core.dto.ServiceDTO;
......@@ -19,9 +23,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;
import org.unidal.net.Networks;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
......@@ -37,6 +43,7 @@ public class ConfigServiceLocator implements Initializable {
private AtomicReference<List<ServiceDTO>> m_configServices;
private Type m_responseType;
private ScheduledExecutorService m_executorService;
private static final Joiner.MapJoiner MAP_JOINER = Joiner.on("&").withKeyValueSeparator("=");
/**
* Create a config service locator.
......@@ -95,10 +102,8 @@ public class ConfigServiceLocator implements Initializable {
m_configUtil.getRefreshTimeUnit());
}
//TODO periodically update config services
private synchronized void updateConfigServices() {
String domainName = m_configUtil.getMetaServerDomainName();
String url = domainName + "/services/config";
String url = assembleMetaServiceUrl();
HttpRequest request = new HttpRequest(url);
int maxRetries = 5;
......@@ -131,6 +136,19 @@ public class ConfigServiceLocator implements Initializable {
throw new RuntimeException("Get config services failed", exception);
}
private String assembleMetaServiceUrl() {
String domainName = m_configUtil.getMetaServerDomainName();
String appId = m_configUtil.getAppId();
String localIp = Networks.forIp().getLocalHostAddress();
Escaper escaper = UrlEscapers.urlPathSegmentEscaper();
Map<String, String> queryParams = Maps.newHashMap();
queryParams.put("appId", escaper.escape(appId));
queryParams.put("ip", escaper.escape(localIp));
return domainName + "/services/config?" + MAP_JOINER.join(queryParams);
}
private void logConfigServicesToCat(List<ServiceDTO> serviceDtos) {
for (ServiceDTO serviceDto : serviceDtos) {
Cat.logEvent("Apollo.Config.Services", serviceDto.getHomepageUrl());
......
......@@ -57,6 +57,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
private final ScheduledExecutorService m_executorService;
private final AtomicBoolean m_longPollingStopped;
private SchedulePolicy m_longPollSchedulePolicy;
private AtomicReference<ServiceDTO> m_longPollServiceDto;
/**
* Constructor.
......@@ -79,6 +80,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
m_longPollingStopped = new AtomicBoolean(false);
m_executorService = Executors.newScheduledThreadPool(1,
ApolloThreadFactory.create("RemoteConfigRepository", true));
m_longPollServiceDto = new AtomicReference<>();
this.trySync();
this.schedulePeriodicRefresh();
this.scheduleLongPollingRefresh();
......@@ -148,8 +150,12 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
List<ServiceDTO> configServices = getConfigServices();
for (int i = 0; i < maxRetries; i++) {
List<ServiceDTO> randomConfigServices = Lists.newArrayList(configServices);
List<ServiceDTO> randomConfigServices = Lists.newLinkedList(configServices);
Collections.shuffle(randomConfigServices);
//Access the server which notifies the client first
if (m_longPollServiceDto.get() != null) {
randomConfigServices.add(0, m_longPollServiceDto.getAndSet(null));
}
for (ServiceDTO configService : randomConfigServices) {
String url =
......@@ -272,6 +278,7 @@ public class RemoteConfigRepository extends AbstractConfigRepository {
logger.debug("Long polling response: {}, url: {}", response.getStatusCode(), url);
if (response.getStatusCode() == 200) {
m_longPollServiceDto.set(lastServiceDto);
longPollingService.submit(new Runnable() {
@Override
public void run() {
......
......@@ -6,6 +6,7 @@ import com.netflix.appinfo.InstanceInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
......@@ -39,7 +40,9 @@ public class ServiceController {
}
@RequestMapping("/config")
public List<ServiceDTO> getConfigService() {
public List<ServiceDTO> getConfigService(
@RequestParam(value = "appId", defaultValue = "") String appId,
@RequestParam(value = "ip", defaultValue = "") String clientIp) {
List<InstanceInfo> instances = discoveryService.getConfigServiceInstances();
List<ServiceDTO> result = instances.stream().map(new Function<InstanceInfo, ServiceDTO>() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment