org.mydotey.artemis.client.discovery.ServiceRepository Maven / Gradle / Ivy
The newest version!
package org.mydotey.artemis.client.discovery;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.mydotey.artemis.Instance;
import org.mydotey.artemis.InstanceChange;
import org.mydotey.artemis.Service;
import org.mydotey.artemis.client.ServiceChangeEvent;
import org.mydotey.artemis.client.ServiceChangeListener;
import org.mydotey.artemis.client.common.ArtemisClientConfig;
import org.mydotey.artemis.discovery.DiscoveryConfig;
import org.mydotey.caravan.util.metric.EventMetric;
import org.mydotey.caravan.util.metric.EventMetricManager;
import org.mydotey.caravan.util.metric.MetricConfig;
import org.mydotey.artemis.util.InstanceChanges;
import org.mydotey.codec.json.JacksonJsonCodec;
import org.mydotey.java.StringExtension;
import org.mydotey.java.collection.CollectionExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Created by fang_j on 10/07/2016.
*/
public class ServiceRepository {
private static final Logger logger = LoggerFactory.getLogger(ServiceRepository.class);
private final ConcurrentHashMap services = new ConcurrentHashMap<>();
private final ConcurrentHashMap discoveryConfigs = new ConcurrentHashMap<>();
private final ExecutorService serviceChangeCallback = Executors.newSingleThreadExecutor();
private final String serviceDiscoveryMetricName;
private final EventMetricManager eventMetricManager;
protected final ServiceDiscovery serviceDiscovery;
public ServiceRepository(final ArtemisClientConfig config) {
this(config, null);
}
protected ServiceRepository(final ArtemisClientConfig config, ServiceDiscovery serviceDiscovery) {
Preconditions.checkArgument(config != null, "ArtemisClientConfig should not be null");
serviceDiscoveryMetricName = config.key("service-discovery.instance-change.event.distribution");
eventMetricManager = config.eventMetricManager();
if (serviceDiscovery == null) {
this.serviceDiscovery = new ServiceDiscovery(this, config);
} else {
this.serviceDiscovery = serviceDiscovery;
}
}
public boolean containsService(final String serviceId) {
if (StringExtension.isBlank(serviceId)) {
return false;
}
return services.containsKey(serviceId.toLowerCase());
}
public List getDiscoveryConfigs() {
return Lists.newArrayList(discoveryConfigs.values());
}
public DiscoveryConfig getDiscoveryConfig(final String serviceId) {
if (StringExtension.isBlank(serviceId)) {
return null;
}
return discoveryConfigs.get(serviceId.toLowerCase());
}
public List getServices() {
return Lists.newArrayList(services.values());
}
public Service getService(final DiscoveryConfig discoveryConfig) {
if (discoveryConfig == null) {
return new Service();
}
final String serviceId = StringExtension.toLowerCase(discoveryConfig.getServiceId());
if (StringExtension.isBlank(serviceId))
return new Service();
if (!containsService(serviceId))
registerService(discoveryConfig);
return services.get(serviceId).newService();
}
public void registerServiceChangeListener(final DiscoveryConfig discoveryConfig,
final ServiceChangeListener listener) {
if ((discoveryConfig == null) || (listener == null)) {
return;
}
final String serviceId = StringExtension.toLowerCase(discoveryConfig.getServiceId());
if (StringExtension.isBlank(serviceId)) {
return;
}
if (!containsService(serviceId)) {
registerService(discoveryConfig);
}
services.get(serviceId).addListener(listener);
}
private synchronized void registerService(final DiscoveryConfig discoveryConfig) {
if (discoveryConfig == null) {
return;
}
final String serviceId = StringExtension.toLowerCase(discoveryConfig.getServiceId());
if (containsService(serviceId)) {
return;
}
ServiceContext serviceContext = new ServiceContext(discoveryConfig);
try {
Service service = serviceDiscovery.getService(discoveryConfig);
serviceContext.setService(service);
} catch (Throwable t) {
logger.error("init service failed", t);
}
services.put(serviceId, serviceContext);
discoveryConfigs.put(serviceId, discoveryConfig);
try {
serviceDiscovery.registerDiscoveryConfig(discoveryConfig);
} catch (final Throwable e) {
logger.warn(String.format("register the service %s to the %s failed", serviceId, serviceDiscovery), e);
}
}
private void notifyServiceChange(final ServiceChangeListener listener, final ServiceChangeEvent event) {
try {
if ((listener == null) || (event == null)) {
return;
}
serviceChangeCallback.submit(new Runnable() {
@Override
public void run() {
try {
listener.onChange(event);
} catch (final Throwable e) {
logger.error("execute service change listener failed", e);
}
}
});
} catch (final Throwable e) {
logger.warn("submit service change notification failed", e);
}
}
protected final synchronized void update(Service service) {
try {
if (service == null) {
return;
}
final String serviceId = service.getServiceId();
if (serviceId == null) {
return;
}
ServiceContext currentContext = services.get(serviceId.toLowerCase());
if (currentContext == null) {
return;
}
currentContext.setService(service);
ServiceChangeEvent event = currentContext.newServiceChangeEvent(InstanceChange.ChangeType.RELOAD);
for (ServiceChangeListener listener : currentContext.getListeners())
notifyServiceChange(listener, event);
logger.info("Operation:" + event.changeType() + "\n" + "service: "
+ new String(JacksonJsonCodec.DEFAULT.encode(service)));
metric(event.changeType(), true, service);
} catch (final Throwable e) {
logger.warn("update service instance failed", e);
}
}
protected final synchronized void update(InstanceChange instanceChange) {
try {
final String changeType = instanceChange.getChangeType();
final Instance instance = instanceChange.getInstance();
if (StringExtension.isBlank(changeType) || instance == null)
return;
final ServiceContext currentContext = services.get(instance.getServiceId());
if (currentContext == null)
return;
boolean updated = false;
if (InstanceChange.ChangeType.DELETE.equals(changeType)) {
updated = currentContext.deleteInstance(instance);
} else if (InstanceChange.ChangeType.NEW.equals(changeType)) {
updated = currentContext.addInstance(instance);
} else if (InstanceChange.ChangeType.CHANGE.equals(changeType)) {
updated = currentContext.updateInstance(instance);
} else {
logger.info("unexpected changeType:" + changeType);
}
if (updated) {
ServiceChangeEvent event = currentContext.newServiceChangeEvent(changeType);
for (ServiceChangeListener listener : currentContext.getListeners()) {
notifyServiceChange(listener, event);
}
logger.info("Operation:" + changeType + "\nInstance: " + instance);
}
metric(changeType, updated, instance);
} catch (Throwable e) {
logger.warn("update service instance failed", e);
}
}
private void metric(String changeType, boolean updated, Service service) {
if (StringExtension.isBlank(changeType) || service == null)
return;
Instance fakeAllInstance = getFakeAllInstance(service);
if (fakeAllInstance == null)
return;
metric(changeType, updated, fakeAllInstance);
}
private Instance getFakeAllInstance(Service service) {
List instances = service.getInstances();
if (CollectionExtension.isEmpty(instances))
return null;
Instance sampleInstance = instances.get(0);
if (sampleInstance == null)
return null;
Instance fakeInstance = sampleInstance.clone();
fakeInstance.setInstanceId(InstanceChanges.RELOAD_FAKE_INSTANCE_ID);
return fakeInstance;
}
private void metric(String changeType, boolean updated, Instance instance) {
if (StringExtension.isBlank(changeType) || instance == null)
return;
String metricId = "service-discovery." + changeType + "." + updated + "." + instance;
Map metadata = Maps.newHashMap();
metadata.put("metric_name_distribution", serviceDiscoveryMetricName);
metadata.put("regionId", instance.getRegionId());
metadata.put("zoneId", instance.getZoneId());
metadata.put("serviceId", instance.getServiceId());
metadata.put("updated", updated ? "true" : "false");
metadata.put("instanceId", instance.getInstanceId());
EventMetric metric = eventMetricManager.getMetric(metricId, new MetricConfig(metadata));
metric.addEvent(changeType);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy