All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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