net.sf.jabb.util.attempt.AttemptBackoffStrategies Maven / Gradle / Ivy
/*
* Copyright 2012-2015 Ray Holder
* Copyright 2015 James Hu
*
* 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 net.sf.jabb.util.attempt;
import java.util.List;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import net.sf.jabb.util.parallel.BackoffStrategy;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
/**
* Factory class for instances of {@link AttemptBackoffStrategy}.
*
* @author JB
* @author James Hu
*/
public final class AttemptBackoffStrategies {
private AttemptBackoffStrategies() {
}
public static AttemptBackoffStrategy simpleBackoff(BackoffStrategy backoffStrategy){
Preconditions.checkNotNull(backoffStrategy, "backoffStrategy may not be null");
return new SimpleBackoffStrategy(backoffStrategy);
}
/**
* Returns a strategy which waits for an amount of time based on the Exception that occurred. The
* {@code function} determines how the wait time should be calculated for the given
* {@code exceptionClass}. If the exception does not match, a wait time of 0 is returned.
*
* @param type of the exception
* @param function function to calculate wait time
* @param exceptionClass class to calculate wait time from
* @return a backoff strategy calculated from the failed attempt
*/
public static AttemptBackoffStrategy exceptionBasedBackoff(@Nonnull Class exceptionClass,
@Nonnull Function function) {
Preconditions.checkNotNull(exceptionClass, "exceptionClass may not be null");
Preconditions.checkNotNull(function, "function may not be null");
return new ExceptionBasedBackoffStrategy(exceptionClass, function);
}
/**
* Joins one or more wait strategies to derive a composite backoff strategy.
* The new joined strategy will have a wait time which is total of all wait times computed one after another in order.
*
* @param waitStrategies Wait strategies that need to be applied one after another for computing the wait time.
* @return A composite backoff strategy
*/
public static AttemptBackoffStrategy join(AttemptBackoffStrategy... waitStrategies) {
Preconditions.checkState(waitStrategies.length > 0, "Must have at least one backoff strategy");
List waitStrategyList = Lists.newArrayList(waitStrategies);
Preconditions.checkState(!waitStrategyList.contains(null), "Cannot have a null backoff strategy");
return new CompositeBackoffStrategy(waitStrategyList);
}
@Immutable
private static final class SimpleBackoffStrategy implements AttemptBackoffStrategy {
private final BackoffStrategy backoffStrategy;
public SimpleBackoffStrategy(BackoffStrategy backoffStrategy){
Preconditions.checkNotNull(backoffStrategy, "backoffStrategy may not be null");
this.backoffStrategy = backoffStrategy;
}
@Override
public long computeBackoffMilliseconds(Attempt attempt) {
return backoffStrategy.computeBackoffMilliseconds(attempt.getTotalAttempts());
}
}
@Immutable
private static final class CompositeBackoffStrategy implements AttemptBackoffStrategy {
private final List waitStrategies;
public CompositeBackoffStrategy(List waitStrategies) {
Preconditions.checkState(!waitStrategies.isEmpty(), "Need at least one backoff strategy");
this.waitStrategies = waitStrategies;
}
@Override
public long computeBackoffMilliseconds(Attempt failedAttempt) {
long waitTime = 0L;
for (AttemptBackoffStrategy waitStrategy : waitStrategies) {
waitTime += waitStrategy.computeBackoffMilliseconds(failedAttempt);
}
return waitTime;
}
}
@Immutable
private static final class ExceptionBasedBackoffStrategy implements AttemptBackoffStrategy {
private final Class exceptionClass;
private final Function function;
public ExceptionBasedBackoffStrategy(@Nonnull Class exceptionClass, @Nonnull Function function) {
this.exceptionClass = exceptionClass;
this.function = function;
}
@SuppressWarnings("unchecked")
@Override
public long computeBackoffMilliseconds(Attempt lastAttempt) {
if (lastAttempt.hasException()) {
Exception cause = lastAttempt.getException();
if (exceptionClass.isAssignableFrom(cause.getClass())) {
return function.apply((T) cause);
}
}
return 0L;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy