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

com.netflix.eureka2.server.service.BridgeChannel Maven / Gradle / Ivy

package com.netflix.eureka2.server.service;

import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Applications;
import com.netflix.eureka2.bridge.InstanceInfoConverter;
import com.netflix.eureka2.bridge.InstanceInfoConverterImpl;
import com.netflix.eureka2.bridge.OperatorInstanceInfoFromV1;
import com.netflix.eureka2.registry.Delta;
import com.netflix.eureka2.registry.InstanceInfo;
import com.netflix.eureka2.server.registry.EurekaServerRegistry;
import com.netflix.eureka2.service.ServiceChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
import rx.functions.Action0;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import rx.subjects.ReplaySubject;
import rx.subjects.Subject;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * A bridge channel that handles changes between snapshots of v1 instanceInfo
 *
 * @author David Liu
 */
public class BridgeChannel implements ServiceChannel {
    private static final Logger logger = LoggerFactory.getLogger(BridgeChannel.class);

    private final EurekaServerRegistry registry;
    private final DiscoveryClient discoveryClient;
    private final InstanceInfoConverter converter;
    private final int refreshRateSec;
    private final Scheduler.Worker worker;
    private Map currentSnapshot;

    private final Subject lifecycle;

    public BridgeChannel(EurekaServerRegistry registry,
                         DiscoveryClient discoveryClient,
                         int refreshRateSec) {
        this.registry = registry;
        this.discoveryClient = discoveryClient;
        this.refreshRateSec = refreshRateSec;

        converter = new InstanceInfoConverterImpl();
        worker = Schedulers.computation().createWorker();
        currentSnapshot = new HashMap<>();

        lifecycle = ReplaySubject.create();
    }

    public void connect() {
        worker.schedulePeriodically(new Action0() {
            @Override
            public void call() {
                logger.info("Starting new round of replication from v1 to v2");
                final AtomicLong totalCount = new AtomicLong(0);  // TODO: servo-fy
                final AtomicLong updateCount = new AtomicLong(0);
                final AtomicLong registerCount = new AtomicLong(0);
                final AtomicLong unregisterCount = new AtomicLong(0);

                final Map newSnapshot = new HashMap<>();

                getV1Stream()
                        .lift(new OperatorInstanceInfoFromV1(converter))
                        .subscribe(new Subscriber() {
                            @Override
                            public void onCompleted() {
                            }

                            @Override
                            public void onError(Throwable e) {
                                logger.warn("error processing v1 stream", e);
                                e.printStackTrace();
                            }

                            @Override
                            public void onNext(InstanceInfo instanceInfo) {
                                totalCount.incrementAndGet();
                                newSnapshot.put(instanceInfo.getId(), instanceInfo);
                                if (currentSnapshot.containsKey(instanceInfo.getId())) {
                                    InstanceInfo older = currentSnapshot.get(instanceInfo.getId());
                                    if (!older.equals(instanceInfo)) {
                                        Set> deltas = older.diffNewer(instanceInfo);
                                        registry.update(instanceInfo, deltas);
                                        updateCount.incrementAndGet();
                                    }
                                } else {
                                    registry.register(instanceInfo);
                                    registerCount.incrementAndGet();
                                }
                            }
                        });

                currentSnapshot.keySet().removeAll(newSnapshot.keySet());
                Observable.from(currentSnapshot.values())
                        .subscribe(new Subscriber() {
                            @Override
                            public void onCompleted() {
                            }

                            @Override
                            public void onError(Throwable e) {
                                logger.warn("error unregistering from v1 stream", e);
                            }

                            @Override
                            public void onNext(InstanceInfo instanceInfo) {
                                registry.unregister(instanceInfo);
                                unregisterCount.incrementAndGet();
                            }
                        });

                currentSnapshot = newSnapshot;

                logger.info("Finished new round of replication from v1 to v2." +
                                " Total: {}, registers: {}, updates: {}, unregisters: {}",
                        totalCount.get(), registerCount.get(), updateCount.get(), unregisterCount.get());
            }
        }, 0, refreshRateSec, TimeUnit.SECONDS);
    }

    protected Observable getV1Stream() {
        Applications applications =
                new Applications(discoveryClient.getApplications().getRegisteredApplications());

        return Observable.from(applications.getRegisteredApplications())
                .flatMap(new Func1>() {
                    @Override
                    public Observable call(Application application) {
                        return Observable.from(application.getInstances());
                    }
                });
    }

    @Override
    public void close() {
        discoveryClient.shutdown();
        registry.shutdown();
        lifecycle.onCompleted();
    }

    @Override
    public Observable asLifecycleObservable() {
        return lifecycle;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy