netflix.ocelli.Instance Maven / Gradle / Ivy
package netflix.ocelli;
import rx.Observable;
import rx.functions.Func1;
import rx.observables.GroupedObservable;
/**
* Representation of a single instance within a pool. Up/Down state is managed via
* an Observable where emitting true means the member is active and false
* means the member is not active (possible due to failure detection). onCompleted
* indicates that the PoolMember has been removed.
*
* @author elandau
*
* @param
*/
public class Instance extends Observable {
private final T value;
private static class KeyedInstance {
private final K key;
private final Instance member;
KeyedInstance(K key, Instance member) {
this.key = key;
this.member = member;
}
}
/**
* Partition Members into multiple partitions based on a partition function.
* It's possible for a member to exist in multiple partitions. Each partition
* is a GroupedObservable of members for that partition alone. This stream can
* be fed into a load balancer.
*
* Partitions are useful in the following use cases.
*
* 1. Hosts are grouped into VIPs where each VIP subset can service a certain subset of
* requests. In the example below API's provided by vip1 can be serviced by Hosts 1,2,3
* whereas API's provied by vip2 can only be serviced by hosts 2 and 3.
*
* VIP : F(Host) -> O(vip) Multiple vips
*
* Host1, Host2, Host3
* Host2, Host3
*
* 2. Shard or hash aware clients using consistent hashing (ex. Cassandra) or sharding (ex. EvCache)
* will opt to send traffic only to nodes that can own the data. The partitioner function
* will return the tokenRangeId or shardId for each host. Note that for replication factor of 1
* each shard will contain only 1 host while for higher replication factors each shard will contain
* multiple hosts (equal to the number of shards) and that these hosts will overlap.
*
* Host1, Host2
* Host2, Host3
* Host3, Host4
* Host4, Host5
*
* @author elandau
*
* @param Client type
* @param The partition key
*/
public static Transformer, GroupedObservable>> partitionBy(final Func1> partitioner) {
return new Transformer, GroupedObservable>>() {
@Override
public Observable>> call(final Observable> o) {
return o
.flatMap(new Func1, Observable>>() {
@Override
public Observable> call(final Instance member) {
return partitioner
.call(member.getValue())
.map(new Func1>() {
@Override
public KeyedInstance call(K key) {
return new KeyedInstance(key, member);
}
});
}
})
.groupBy(
new Func1, K>() {
@Override
public K call(KeyedInstance t1) {
return t1.key;
}
},
new Func1, Instance>() {
@Override
public Instance call(KeyedInstance t1) {
return t1.member;
}
});
}
};
}
public Instance(T value, OnSubscribe state) {
super(state);
this.value = value;
}
public T getValue() {
return this.value;
}
public String toString() {
return "Member[" + value + "]";
}
}