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

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

/*
 * Copyright 2014 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.eureka2.server.service;

import com.netflix.eureka2.interests.ChangeNotification;
import com.netflix.eureka2.interests.Interest;
import com.netflix.eureka2.interests.MultipleInterests;
import com.netflix.eureka2.registry.InstanceInfo;
import com.netflix.eureka2.server.registry.EurekaServerRegistry;
import com.netflix.eureka2.utils.rx.BreakerSwitchOperator;
import rx.Observable;
import rx.subjects.PublishSubject;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Interest notification multiplexer is channel scoped object, so we can depend here on its
 * single-threaded property from the channel side. However as we subscribe to multiple observables
 * we need to merge them properly. For that we use {@link rx.Observable#merge} with atomic observable
 * streams wrapped by {@link BreakerSwitchOperator}, which allows us to close the notification
 * stream during interest upgrades with interest removal.
 *
 * @author Tomasz Bak
 */
public class InterestNotificationMultiplexer {

    private final EurekaServerRegistry eurekaRegistry;

    private final Map, BreakerSwitchOperator> subscriptionBreakers = new HashMap<>();

    private final PublishSubject>> upgrades = PublishSubject.create();
    private final Observable> aggregatedStream = Observable.merge(upgrades);

    public InterestNotificationMultiplexer(EurekaServerRegistry eurekaRegistry) {
        this.eurekaRegistry = eurekaRegistry;
    }

    /**
     * For composite interest, we flatten it first, and than make parallel subscriptionBreakers to the registry.
     */
    public void update(Interest newInterest) {
        if (newInterest instanceof MultipleInterests) {
            Set> newInterestSet = ((MultipleInterests) newInterest).flatten();
            // Remove interests not present in the new subscription
            Set> toRemove = new HashSet<>(subscriptionBreakers.keySet());
            toRemove.removeAll(newInterestSet);
            for (Interest item : toRemove) {
                removeInterest(item);
            }
            // Add new interests
            Set> toAdd = new HashSet<>(newInterestSet);
            toAdd.removeAll(subscriptionBreakers.keySet());
            for (Interest item : toAdd) {
                subscribeToInterest(item);
            }
        } else {
            // First remove all interests except the current one if present
            Set> toRemove = new HashSet<>(subscriptionBreakers.keySet());
            toRemove.remove(newInterest);
            for (Interest item : toRemove) {
                removeInterest(item);
            }
            // Add new interests
            if (subscriptionBreakers.isEmpty()) {
                subscribeToInterest(newInterest);
            }
        }
    }

    private void subscribeToInterest(Interest newInterest) {
        BreakerSwitchOperator breaker = new BreakerSwitchOperator();
        upgrades.onNext(eurekaRegistry.forInterest(newInterest).lift(breaker));
        subscriptionBreakers.put(newInterest, breaker);
    }

    private void removeInterest(Interest currentInterest) {
        subscriptionBreakers.remove(currentInterest).close();
    }

    public void unregister() {
        for (BreakerSwitchOperator subject : subscriptionBreakers.values()) {
            subject.close();
        }
        subscriptionBreakers.clear();
    }

    /**
     * Interest channel creates a single subscription to this observable prior to
     * registering any interest set. We can safely use hot observable, which
     * simplifies implementation of the multiplexer.
     */
    public Observable> changeNotifications() {
        return aggregatedStream;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy