org.mydotey.artemis.client.discovery.ServiceDiscovery Maven / Gradle / Ivy
The newest version!
package org.mydotey.artemis.client.discovery;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.mydotey.artemis.InstanceChange;
import org.mydotey.artemis.Service;
import org.mydotey.artemis.client.common.ArtemisClientConfig;
import org.mydotey.artemis.client.websocket.WebSocketSessionContext;
import org.mydotey.scf.filter.RangeValueConfig;
import org.mydotey.scf.filter.RangeValueFilter;
import org.mydotey.artemis.discovery.DiscoveryConfig;
import org.mydotey.caravan.util.concurrent.DynamicScheduledThread;
import org.mydotey.caravan.util.concurrent.DynamicScheduledThreadConfig;
import org.mydotey.codec.json.JacksonJsonCodec;
import org.mydotey.java.StringExtension;
import org.mydotey.scf.Property;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import java.util.List;
import java.util.Map;
/**
* Created by fang_j on 10/07/2016.
*/
public class ServiceDiscovery {
private static final Logger logger = LoggerFactory.getLogger(ServiceDiscovery.class);
private final ServiceRepository serviceRepository;
private final ArtemisDiscoveryHttpClient discoveryHttpClient;
private final Property ttl;
private volatile long lastUpdateTime = System.currentTimeMillis();
private final WebSocketSessionContext sessionContext;
private final DynamicScheduledThread poller;
protected final Map reloadFailedDiscoveryConfigs = Maps.newConcurrentMap();
public ServiceDiscovery(final ServiceRepository serviceRepository, final ArtemisClientConfig config) {
Preconditions.checkArgument(serviceRepository != null, "ServiceRepository should not be null");
this.serviceRepository = serviceRepository;
this.discoveryHttpClient = new ArtemisDiscoveryHttpClient(config);
ttl = config.properties().getLongProperty(config.key("service-discovery.ttl"), 15 * 60 * 1000L,
new RangeValueFilter<>(60 * 1000L, 24 * 60 * 60 * 1000L));
sessionContext = new WebSocketSessionContext(config) {
@Override
protected void afterConnectionEstablished(final WebSocketSession session) {
subscribe(session);
}
@Override
protected void handleMessage(final WebSocketSession session, final WebSocketMessage> message) {
try {
InstanceChange instanceChange = JacksonJsonCodec.DEFAULT
.decode(((String) message.getPayload()).getBytes(), InstanceChange.class);
onInstanceChange(instanceChange);
} catch (final Throwable e) {
logger.warn("convert message failed", e);
}
}
};
sessionContext.start();
final DynamicScheduledThreadConfig dynamicScheduledThreadConfig = new DynamicScheduledThreadConfig(
config.properties(),
new RangeValueConfig(0, 0, 200),
new RangeValueConfig(60 * 1000, 60 * 1000, 24 * 60 * 60 * 1000));
poller = new DynamicScheduledThread(config.key("service-discovery"), () -> {
try {
reload(getReloadDiscoveryConfigs());
} catch (Throwable t) {
logger.warn("reload services failed", t);
}
}, dynamicScheduledThreadConfig);
poller.setDaemon(true);
poller.start();
}
public void registerDiscoveryConfig(DiscoveryConfig config) {
subscribe(sessionContext.get(), config);
}
public Service getService(DiscoveryConfig config) {
return discoveryHttpClient.getService(config);
}
protected void onServiceChange(Service service) {
serviceRepository.update(service);
}
protected void onInstanceChange(InstanceChange instanceChange) {
final String serviceId = instanceChange.getInstance().getServiceId();
if (InstanceChange.ChangeType.RELOAD.equals(instanceChange.getChangeType())) {
reload(serviceRepository.getDiscoveryConfig(serviceId));
} else {
serviceRepository.update(instanceChange);
}
}
protected List getReloadDiscoveryConfigs() {
if (expired()) {
return serviceRepository.getDiscoveryConfigs();
}
Map discoveryConfigs = Maps.newHashMap(reloadFailedDiscoveryConfigs);
List configs = Lists.newArrayList(discoveryConfigs.values());
for (ServiceContext serviceContext : serviceRepository.getServices()) {
if (discoveryConfigs.containsKey(serviceContext.getDiscoveryConfig().getServiceId())
|| serviceContext.isAvailable()) {
continue;
}
configs.add(serviceContext.getDiscoveryConfig());
}
return configs;
}
protected void reload(DiscoveryConfig... configs) {
reload(Lists.newArrayList(configs));
}
protected void reload(List configs) {
try {
if (CollectionUtils.isEmpty(configs))
return;
logger.info("start reload services.");
List services = discoveryHttpClient.getServices(configs);
for (Service service : services) {
if (service == null) {
continue;
}
final String serviceId = service.getServiceId();
if (StringExtension.isBlank(serviceId)) {
continue;
}
onServiceChange(service);
reloadFailedDiscoveryConfigs.remove(serviceId.toLowerCase());
}
lastUpdateTime = System.currentTimeMillis();
logger.info("end reload services");
} catch (Throwable t) {
for (DiscoveryConfig config : configs) {
if (config == null) {
continue;
}
final String serviceId = config.getServiceId();
if (StringExtension.isBlank(serviceId)) {
continue;
}
reloadFailedDiscoveryConfigs.put(serviceId.toLowerCase(), config);
}
throw t;
}
}
protected void subscribe(final WebSocketSession session) {
try {
for (final DiscoveryConfig discoveryConfig : serviceRepository.getDiscoveryConfigs()) {
subscribe(session, discoveryConfig);
}
} catch (final Throwable e) {
logger.warn("subscribe services failed", e);
}
}
protected void subscribe(final WebSocketSession session, final DiscoveryConfig discoveryConfig) {
try {
if (discoveryConfig == null) {
return;
}
if (session == null) {
return;
}
final TextMessage message = new TextMessage(new String(
JacksonJsonCodec.DEFAULT.encode(discoveryConfig)));
session.sendMessage(message);
} catch (final Throwable e) {
logger.warn("subscribe service failed", e);
}
}
protected boolean expired() {
return System.currentTimeMillis() - lastUpdateTime >= ttl.getValue();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy