netflix.ocelli.loadbalancer.FallbackLoadBalancer Maven / Gradle / Ivy
package netflix.ocelli.loadbalancer;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import netflix.ocelli.LoadBalancer;
import netflix.ocelli.functions.Retrys;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;
/**
* Composite load balancer that cascades through a set of load balancers until one has a client.
* This type load balancer should be used for use cases such as DC and Vip failover.
*
* In the following example the fallback load balancer will first attempt to choose a client from
* dc1 and switch to dc2 if no clients exist in dc1.
*
* {@code
*
* LoadBalancer dc1 = RoundRobinLoadBalancer.create();
* LoadBalancer dc2 = RoundRobinLoadBalancer.create();
*
* LoadBalancer fallback = new FallbackLoadBalancer(Lists.newArrayList(dc1, dc2));
* fallback.subscribe(clientHandler);
*
*
* }
* @author elandau
*
* @param
*/
public class FallbackLoadBalancer extends LoadBalancer {
public FallbackLoadBalancer(final List> lbs, Func1 isRetriable) {
super(new FallbackOnSubscribe(lbs, isRetriable));
}
public FallbackLoadBalancer(final List> lbs) {
this(lbs, Retrys.ALWAYS);
}
private static class FallbackOnSubscribe implements OnSubscribe {
private final List> lbs;
private final Func1 isRetriable;
FallbackOnSubscribe(List> lbs, Func1 isRetriable) {
this.lbs = lbs;
this.isRetriable = isRetriable;
}
@Override
public void call(Subscriber super C> s) {
_call(lbs.iterator(), s);
}
private void _call(final Iterator> iter, Subscriber super C> s) {
if (iter.hasNext()) {
iter.next().onErrorResumeNext(new Func1>() {
@Override
public Observable call(Throwable t1) {
if (!isRetriable.call(t1)) {
return Observable.empty();
}
return Observable.create(new OnSubscribe() {
@Override
public void call(Subscriber super C> t1) {
_call(iter, t1);
}
});
}
})
.subscribe(s);
}
else {
s.onError(new NoSuchElementException());
}
}
}
@Override
public void call(List t1) {
// No op
}
}