com.github.phantomthief.failover.impl.WeightFailoverBuilder Maven / Gradle / Ivy
package com.github.phantomthief.failover.impl;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
import javax.annotation.CheckReturnValue;
import org.slf4j.Logger;
public class WeightFailoverBuilder {
private static final Logger logger = getLogger(WeightFailoverBuilder.class);
private static final int DEFAULT_INIT_WEIGHT = 100;
private static final int DEFAULT_FAIL_REDUCE_WEIGHT = 5;
private static final int DEFAULT_SUCCESS_INCREASE_WEIGHT = 1;
private static final int DEFAULT_RECOVERED_INIT_WEIGHT = 1;
private static final long DEFAULT_CHECK_DURATION = SECONDS.toMillis(1);
private IntUnaryOperator failReduceWeight;
private IntUnaryOperator successIncreaseWeight;
private IntUnaryOperator recoveredInitWeight;
private Map initWeightMap;
private Predicate checker;
private long checkDuration;
private Consumer onMinWeight;
private Consumer onRecovered;
private int minWeight = 0;
@CheckReturnValue
@SuppressWarnings("unchecked")
public WeightFailoverBuilder onMinWeight(Consumer listener) {
checkNotNull(listener);
WeightFailoverBuilder thisBuilder = (WeightFailoverBuilder) this;
thisBuilder.onMinWeight = listener;
return thisBuilder;
}
@CheckReturnValue
@SuppressWarnings("unchecked")
public WeightFailoverBuilder onRecovered(Consumer listener) {
checkNotNull(listener);
WeightFailoverBuilder thisBuilder = (WeightFailoverBuilder) this;
thisBuilder.onRecovered = listener;
return thisBuilder;
}
@CheckReturnValue
public WeightFailoverBuilder minWeight(int value) {
checkArgument(value >= 0);
this.minWeight = value;
return this;
}
@CheckReturnValue
public WeightFailoverBuilder failReduceRate(double rate) {
checkArgument(rate > 0 && rate <= 1);
failReduceWeight = i -> Math.max(1, (int) (rate * i));
return this;
}
@CheckReturnValue
public WeightFailoverBuilder failReduce(int weight) {
checkArgument(weight > 0);
failReduceWeight = i -> weight;
return this;
}
@CheckReturnValue
public WeightFailoverBuilder successIncreaseRate(double rate) {
checkArgument(rate > 0 && rate <= 1);
successIncreaseWeight = i -> Math.max(1, (int) (rate * i));
return this;
}
@CheckReturnValue
public WeightFailoverBuilder successIncrease(int weight) {
checkArgument(weight > 0);
successIncreaseWeight = i -> weight;
return this;
}
@CheckReturnValue
public WeightFailoverBuilder recoveredInitRate(double rate) {
checkArgument(rate > 0 && rate <= 1);
recoveredInitWeight = i -> Math.max(1, (int) (rate * i));
return this;
}
@CheckReturnValue
public WeightFailoverBuilder recoveredInit(int weight) {
checkArgument(weight > 0);
recoveredInitWeight = i -> weight;
return this;
}
@CheckReturnValue
public WeightFailoverBuilder checkDuration(long time, TimeUnit unit) {
checkNotNull(unit);
checkArgument(time > 0);
checkDuration = unit.toMillis(time);
return this;
}
@SuppressWarnings("unchecked")
@CheckReturnValue
public WeightFailoverBuilder checker(Predicate super E> failChecker) {
checkNotNull(failChecker);
WeightFailoverBuilder thisBuilder = (WeightFailoverBuilder) this;
thisBuilder.checker = t -> {
try {
return failChecker.test(t);
} catch (Throwable e) {
logger.error("", e);
return false;
}
};
return thisBuilder;
}
public WeightFailover build(Collection extends E> original) {
return build(original, DEFAULT_INIT_WEIGHT);
}
public WeightFailover build(Collection extends E> original, int initWeight) {
checkNotNull(original);
checkArgument(initWeight > 0);
return build(original.stream().collect(toMap(identity(), i -> initWeight, (u, v) -> u)));
}
@SuppressWarnings("unchecked")
public WeightFailover build(Map extends E, Integer> original) {
checkNotNull(original);
WeightFailoverBuilder thisBuilder = (WeightFailoverBuilder) this;
thisBuilder.initWeightMap = (Map) original;
return thisBuilder.build();
}
private WeightFailover build() {
ensure();
return new WeightFailover<>(failReduceWeight, successIncreaseWeight, recoveredInitWeight,
initWeightMap, minWeight, checkDuration, checker, onMinWeight, onRecovered);
}
private void ensure() {
checkNotNull(checker);
if (failReduceWeight == null) {
failReduceWeight = i -> DEFAULT_FAIL_REDUCE_WEIGHT;
}
if (successIncreaseWeight == null) {
successIncreaseWeight = i -> DEFAULT_SUCCESS_INCREASE_WEIGHT;
}
if (recoveredInitWeight == null) {
recoveredInitWeight = i -> DEFAULT_RECOVERED_INIT_WEIGHT;
}
if (checkDuration == 0) {
checkDuration = DEFAULT_CHECK_DURATION;
}
}
}