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

com.netflix.eureka2.client.registry.EurekaClientRegistryProxy Maven / Gradle / Ivy

package com.netflix.eureka2.client.registry;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.netflix.eureka2.client.channel.ClientChannelFactory;
import com.netflix.eureka2.client.channel.ClientInterestChannel;
import com.netflix.eureka2.client.channel.consumer.RetryableChannelConsumer;
import com.netflix.eureka2.client.metric.EurekaClientMetricFactory;
import com.netflix.eureka2.client.registry.EurekaClientRegistryProxy.RegistryTracker;
import com.netflix.eureka2.client.registry.swap.RegistrySwapOperator;
import com.netflix.eureka2.client.registry.swap.RegistrySwapStrategyFactory;
import com.netflix.eureka2.interests.ChangeNotification;
import com.netflix.eureka2.interests.Interest;
import com.netflix.eureka2.interests.MultipleInterests;
import com.netflix.eureka2.registry.Delta;
import com.netflix.eureka2.registry.EurekaRegistry;
import com.netflix.eureka2.registry.InstanceInfo;
import com.netflix.eureka2.service.InterestChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Scheduler;
import rx.Subscriber;
import rx.functions.Action0;
import rx.observers.Subscribers;
import rx.schedulers.Schedulers;

/**
 * An implementation of {@link EurekaRegistry} to be used by the eureka client.
 *
 * This registry abstracts the {@link InterestChannel} interaction from the consumers of this registry and transparently
 * reconnects when a channel is broken.
 *
 * 

Storage

* * This registry uses {@link EurekaClientRegistryImpl} for actual data storage. * *

Reconnects

* * Whenever the used {@link InterestChannel} is broken, this class holds the last known registry information till the * time it is successfully able to reconnect and relay the last know interest set to the new {@link InterestChannel}. * On a successful reconnect, the old registry data is disposed and the registry is created afresh from the instance * stream from the new {@link InterestChannel} * * @author Nitesh Kant */ @Singleton public class EurekaClientRegistryProxy extends RetryableChannelConsumer implements EurekaClientRegistry { private static final Logger logger = LoggerFactory.getLogger(EurekaClientRegistryProxy.class); public static final long DEFAULT_INITIAL_DELAY = 80; private static final Throwable CHANNEL_FAILURE = new Exception( "There was a communication failure, and connection has been reestablished; a new subscription is required"); private final ClientChannelFactory channelFactory; private final RegistrySwapStrategyFactory swapStrategyFactory; private final EurekaClientMetricFactory metricFactory; @Inject public EurekaClientRegistryProxy(ClientChannelFactory channelFactory, RegistrySwapStrategyFactory swapStrategyFactory, long retryInitialDelayMs, EurekaClientMetricFactory metricFactory) { this(channelFactory, swapStrategyFactory, retryInitialDelayMs, metricFactory, Schedulers.computation()); } public EurekaClientRegistryProxy(ClientChannelFactory channelFactory, RegistrySwapStrategyFactory swapStrategyFactory, long retryInitialDelayMs, EurekaClientMetricFactory metricFactory, Scheduler scheduler) { super(retryInitialDelayMs, scheduler); this.channelFactory = channelFactory; this.metricFactory = metricFactory; this.swapStrategyFactory = swapStrategyFactory; initializeRetryableConsumer(); } @Override public Observable register(InstanceInfo instanceInfo) { throw new IllegalArgumentException("Proxy registry modification not allowed"); } @Override public Observable unregister(InstanceInfo instanceInfo) { throw new IllegalArgumentException("Proxy registry modification not allowed"); } @Override public Observable update(InstanceInfo updatedInfo, Set> deltas) { throw new IllegalArgumentException("Proxy registry modification not allowed"); } @Override public int size() { return getCurrentRegistry().size(); } @Override public Observable forSnapshot(Interest interest) { return getCurrentRegistry().forSnapshot(interest); } @Override @SuppressWarnings({"unchecked", "rawtypes"}) public Observable> forInterest(final Interest interest) { StateWithChannel current = getStateWithChannel(); ClientInterestChannel currentChannel = current.getChannel(); RegistryTracker currentState = current.getState(); Observable toReturn = currentChannel .appendInterest(interest).cast(ChangeNotification.class) .doOnCompleted(currentState.createAddInterestAction(interest)) .mergeWith(currentState.registry.forInterest(interest)) .doOnTerminate(currentState.createRemoveInterestAction(interest)); return toReturn; } @Override public Observable shutdown() { return Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber subscriber) { shutdownRetryableConsumer(); channelFactory.shutdown(); // channelFactory will shutdown registry and transport clients } }); } @Override public Observable shutdown(Throwable cause) { throw new IllegalArgumentException("EurekaClientRegistryProxy supports regular shutdown only"); } @Override protected StateWithChannel reestablish() { final RegistryTracker newState = new RegistryTracker(); final ClientInterestChannel newChannel = channelFactory.newInterestChannel(newState.registry); return new StateWithChannel(newChannel, newState); } @Override protected Observable repopulate(StateWithChannel newStateWithChannel) { final RegistryTracker previousState = getStateWithChannel().getState(); final RegistryTracker newState = newStateWithChannel.getState(); final ClientInterestChannel newChannel = newStateWithChannel.getChannel(); return Observable.create(new OnSubscribe() { @Override public void call(final Subscriber subscriber) { // Resubscribe Interest activeInterests = new MultipleInterests(previousState.interests.keySet()); newChannel.change(activeInterests).subscribe(); // Wait until registry fills up to the expected level. newState.registry.forInterest(activeInterests).lift( new RegistrySwapOperator(previousState.registry, newState.registry, swapStrategyFactory) ).subscribe(Subscribers.from(subscriber)); } }); } @Override protected void release(StateWithChannel oldState) { oldState.getState().registry.shutdown(CHANNEL_FAILURE); } private EurekaClientRegistry getCurrentRegistry() { return getStateWithChannel().getState().registry; } /** * {@link RegistryTracker} keeps a reference counted collection of interests, so in case of channel failure * we can silently reconnect and re-subscribe. */ class RegistryTracker { final EurekaClientRegistry registry = new EurekaClientRegistryImpl(metricFactory.getRegistryMetrics()); final ConcurrentMap, AtomicInteger> interests = new ConcurrentHashMap<>(); Action0 createAddInterestAction(final Interest interest) { return new Action0() { @Override public void call() { AtomicInteger newCounter = new AtomicInteger(1); AtomicInteger currentCounter = interests.putIfAbsent(interest, newCounter); if (currentCounter != null) { currentCounter.incrementAndGet(); } } }; } Action0 createRemoveInterestAction(final Interest interest) { return new Action0() { @Override public void call() { AtomicInteger currentCounter = interests.get(interest); if (currentCounter != null) { currentCounter.decrementAndGet(); } } }; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy