Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.spf4j.failsafe.RetryPolicy Maven / Gradle / Ivy
Go to download
A continuously growing collection of utilities to measure performance, get better diagnostics,
improve performance, or do things more reliably, faster that other open source libraries...
/*
* Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Additionally licensed with:
*
* 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 org.spf4j.failsafe;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.CheckReturnValue;
import javax.annotation.ParametersAreNonnullByDefault;
import org.slf4j.Logger;
import org.slf4j.helpers.NOPLogger;
import org.spf4j.base.Throwables;
import org.spf4j.failsafe.concurrent.DefaultFailSafeExecutor;
import org.spf4j.failsafe.concurrent.FailSafeExecutor;
/**
* @author Zoltan Farkas
*/
@ParametersAreNonnullByDefault
@SuppressFBWarnings("FCCD_FIND_CLASS_CIRCULAR_DEPENDENCY")
public class RetryPolicy> implements SyncRetryExecutor {
private static final RetryPolicy> DEFAULT;
static {
RetryPolicy p;
String policySupplierClass = System.getProperty("spf4j.failsafe.defaultRetryPolicySupplier");
if (policySupplierClass == null) {
p = RetryPolicy.newBuilder()
.withDefaultThrowableRetryPredicate()
.withRetryOnException(Exception.class, 2) // will retry any other exception twice.
.build();
} else {
try {
p = ((Supplier) Class.forName(policySupplierClass).newInstance()).get();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
throw new ExceptionInInitializerError(ex);
}
}
DEFAULT = p;
}
private static final RetryPolicy> NO_RETRY
= RetryPolicy.newBuilder().build();
private final TimedSupplier> retryPredSupplier;
private final int maxExceptionChain;
RetryPolicy(final TimedSupplier> retryPredicate,
final int maxExceptionChain) {
this.retryPredSupplier = retryPredicate;
this.maxExceptionChain = maxExceptionChain;
}
public static > RetryPolicy noRetryPolicy() {
return (RetryPolicy) NO_RETRY;
}
public static > RetryPolicy defaultPolicy() {
return (RetryPolicy) DEFAULT;
}
@Override
public final R call(
final W pwhat, final Class exceptionClass, final long startNanos, final long deadlineNanos)
throws InterruptedException, TimeoutException, E {
return (R) SyncRetryExecutor.call(pwhat, getRetryPredicate(startNanos, deadlineNanos),
exceptionClass, maxExceptionChain);
}
public final AsyncRetryExecutor async(final FailSafeExecutor exec) {
return new AsyncRetryExecutorImpl<>(this, HedgePolicy.DEFAULT, exec);
}
public final AsyncRetryExecutor async(final HedgePolicy hedgePolicy, final FailSafeExecutor exec) {
return new AsyncRetryExecutorImpl<>(this, hedgePolicy, exec);
}
public final AsyncRetryExecutor async(final Function hedgePolicy,
final FailSafeExecutor exec) {
return new AsyncRetryExecutorImpl<>(c -> this, hedgePolicy, exec);
}
public static > AsyncRetryExecutor
async(final Function> retry,
final Function hedgePolicy,
final FailSafeExecutor exec) {
return new AsyncRetryExecutorImpl<>(retry, hedgePolicy, exec);
}
public final AsyncRetryExecutor async() {
return async(DefaultFailSafeExecutor.instance());
}
public final RetryPredicate getRetryPredicate(final long startTimeNanos, final long deadlineNanos) {
return new TimeoutRetryPredicate(retryPredSupplier.get(startTimeNanos, deadlineNanos), deadlineNanos);
}
/**
* @return string representation of policy.
*/
@Override
public String toString() {
return "RetryPolicy{retryPredicate=" + retryPredSupplier
+ ", maxExceptionChain=" + maxExceptionChain + '}';
}
public static final class Builder> {
private static final int MAX_EX_CHAIN_DEFAULT = Integer.getInteger("spf4j.failsafe.defaultMaxExceptionChain", 5);
private static final long DEFAULT_MAX_DELAY_NANOS
= TimeUnit.MILLISECONDS.toNanos(Long.getLong("spf4j.failsafe.defaultMaxRetryDelayMillis", 5000));
private static final long DEFAULT_INITIAL_DELAY_NANOS
= Long.getLong("spf4j.failsafe.defaultInitialRetryDelayNanos", 10000);
private static final int DEFAULT_INITIAL_NODELAY_RETRIES
= Integer.getInteger("spf4j.failsafe.defaultInitialNoDelayRetries", 3);
private static final int DEFAULT_MAX_NR_RETRIES
= Integer.getInteger("spf4j.failsafe.defaultMaxNrRetries", 1000);
private int maxExceptionChain = MAX_EX_CHAIN_DEFAULT;
private final List>> resultPredicates;
private final List>> exceptionPredicates;
private int nrInitialImmediateRetries;
private long startDelayNanos;
private long maxDelayNanos;
private double jitterFactor;
private Logger log;
private Builder() {
this.nrInitialImmediateRetries = DEFAULT_INITIAL_NODELAY_RETRIES;
this.startDelayNanos = DEFAULT_INITIAL_DELAY_NANOS;
this.maxDelayNanos = DEFAULT_MAX_DELAY_NANOS;
this.jitterFactor = 0.2;
this.resultPredicates = new ArrayList<>(2);
this.exceptionPredicates = new ArrayList<>(2);
this.log = null;
}
private Builder(final Builder from) {
this.nrInitialImmediateRetries = from.nrInitialImmediateRetries;
this.startDelayNanos = from.startDelayNanos;
this.maxDelayNanos = from.maxDelayNanos;
this.jitterFactor = from.jitterFactor;
this.resultPredicates = new ArrayList(from.resultPredicates);
this.exceptionPredicates = new ArrayList<>(from.exceptionPredicates);
this.log = from.log;
}
public Builder withRetryLogger(final Logger plog) {
this.log = plog;
return this;
}
public Builder withoutRetryLogger() {
this.log = NOPLogger.NOP_LOGGER;
return this;
}
public Builder withDefaultThrowableRetryPredicate() {
return withDefaultThrowableRetryPredicate(DEFAULT_MAX_NR_RETRIES);
}
public Builder withDefaultThrowableRetryPredicate(final int maxNrRetries) {
return withExceptionPartialPredicate((e, c) -> Throwables.isRetryable(e) ? RetryDecision.retryDefault(c) : null,
maxNrRetries);
}
public Builder withRetryOnException(final Class extends Exception> clasz) {
return withRetryOnException(clasz, DEFAULT_MAX_NR_RETRIES);
}
public Builder withRetryOnException(final Class extends Exception> clasz, final int maxRetries) {
return withExceptionPartialPredicate((e, c)
-> clasz.isAssignableFrom(e.getClass())
? RetryDecision.retryDefault(c) : null, maxRetries);
}
public Builder withRetryOnException(final Class extends Exception> clasz,
final long maxTime, final TimeUnit tu) {
return withExceptionPartialPredicate((e, c)
-> clasz.isAssignableFrom(e.getClass())
? RetryDecision.retryDefault(c) : null, maxTime, tu);
}
public Builder withExceptionPartialPredicate(final PartialExceptionRetryPredicate predicate,
final long maxTime, final TimeUnit tu) {
return withExceptionPartialPredicateSupplier((s, d)
-> {
TimeLimitedPartialRetryPredicate p =
new TimeLimitedPartialRetryPredicate<>(s, d, maxTime, tu, 1.0d, predicate);
return (PartialExceptionRetryPredicate) (Throwable value, C what) -> p.apply(value, what);
});
}
public Builder withExceptionPartialPredicate(
final PartialExceptionRetryPredicate predicate) {
return withExceptionPartialPredicateSupplier(TimedSupplier.constant(predicate));
}
public Builder withExceptionPartialPredicate(final Class clasz,
final PartialTypedExceptionRetryPredicate predicate) {
return withExceptionPartialPredicate((e, c) -> {
if (clasz.isAssignableFrom(e.getClass())) {
return predicate.getExceptionDecision((E) e, c);
}
return null;
});
}
public Builder withExceptionPartialPredicate(final Class clasz,
final PartialTypedExceptionRetryPredicate predicate, final int maxRetries) {
return withExceptionPartialPredicate((e, c) -> {
if (clasz.isAssignableFrom(e.getClass())) {
return predicate.getExceptionDecision((E) e, c);
}
return null;
}, maxRetries);
}
public Builder withExceptionPartialPredicate(
final PartialExceptionRetryPredicate predicate,
final int maxRetries) {
return withExceptionPartialPredicateSupplier((s, e) -> {
CountLimitedPartialRetryPredicate p
= new CountLimitedPartialRetryPredicate(maxRetries, predicate);
return (Throwable value, C what) -> p.apply(value, what);
});
}
public Builder withExceptionPartialPredicateSupplier(
final Supplier> predicateSupplier) {
return withExceptionPartialPredicateSupplier((s, e) -> predicateSupplier.get());
}
@Deprecated
public Builder withExceptionStatefulPartialPredicate(
final Supplier> predicateSupplier) {
return Builder.this.withExceptionPartialPredicateSupplier(predicateSupplier);
}
public Builder withExceptionPartialPredicateSupplier(
final TimedSupplier> predicateSupplier) {
exceptionPredicates.add(predicateSupplier);
return this;
}
@Deprecated
public Builder withExceptionStatefulPartialPredicate(
final TimedSupplier> predicateSupplier) {
return withExceptionPartialPredicateSupplier(predicateSupplier);
}
public Builder withRetryOnResult(final T result, final int maxRetries) {
return withResultPartialPredicate((r, c)
-> Objects.equals(result, r)
? RetryDecision.retryDefault(c) : null, maxRetries);
}
public Builder withResultPartialPredicate(
final PartialResultRetryPredicate predicate) {
resultPredicates.add(TimedSupplier.constant(predicate));
return this;
}
@SuppressWarnings("unchecked")
public Builder withResultPartialPredicate(
final Class clasz,
final PartialResultRetryPredicate > predicate) {
resultPredicates.add(TimedSupplier.constant((o, c)
-> (o != null && clasz.isAssignableFrom(o.getClass()))
? predicate.getDecision((A) o, (Callable) c) : null
));
return this;
}
public Builder withResultPartialPredicate(
final PartialResultRetryPredicate predicate,
final int maxRetries) {
return withResultPartialPredicateSupplier((s, e) -> {
CountLimitedPartialRetryPredicate p = new CountLimitedPartialRetryPredicate<>(maxRetries, predicate);
return (T value, C what) -> p.apply(value, what);
});
}
public Builder withResultPartialPredicateSupplier(
final Supplier> predicateSupplier) {
return withResultPartialPredicateSupplier((s, e) -> predicateSupplier.get());
}
@Deprecated
public Builder withResultStatefulPartialPredicate(
final Supplier> predicateSupplier) {
return Builder.this.withResultPartialPredicateSupplier(predicateSupplier);
}
public Builder withResultPartialPredicateSupplier(
final TimedSupplier> predicateSupplier) {
resultPredicates.add(predicateSupplier);
return this;
}
@Deprecated
public Builder withResultStatefulPartialPredicate(
final TimedSupplier> predicateSupplier) {
return withResultPartialPredicateSupplier(predicateSupplier);
}
public Builder withJitterFactor(final double jitterfactor) {
if (jitterFactor > 1 || jitterFactor < 0) {
throw new IllegalArgumentException("Invalid jitter factor " + jitterfactor);
}
this.jitterFactor = jitterfactor;
return this;
}
/**
* @deprecated use withInitialImmediateRetries instead.
*/
@Deprecated
public Builder withInitialRetries(final int retries) {
this.nrInitialImmediateRetries = retries;
return this;
}
public Builder withInitialImmediateRetries(final int retries) {
this.nrInitialImmediateRetries = retries;
return this;
}
public Builder withInitialDelay(final long delay, final TimeUnit unit) {
this.startDelayNanos = unit.toNanos(delay);
return this;
}
public Builder withMaxDelay(final long delay, final TimeUnit unit) {
this.maxDelayNanos = unit.toNanos(delay);
return this;
}
public Builder withMaxExceptionChain(final int maxExChain) {
maxExceptionChain = maxExChain;
return this;
}
@CheckReturnValue
public Builder copy() {
return new Builder<>(this);
}
@CheckReturnValue
public RetryPolicy build() {
TimedSupplier[] rps = resultPredicates.toArray(new TimedSupplier[resultPredicates.size()]);
TimedSupplier[] eps = exceptionPredicates.toArray(new TimedSupplier[exceptionPredicates.size()]);
TimedSupplier> retryPredicate
= (s, e) -> new DefaultRetryPredicate(log, s, e, () -> new TypeBasedRetryDelaySupplier<>(
x -> new JitteredDelaySupplier(new FibonacciRetryDelaySupplier(nrInitialImmediateRetries,
startDelayNanos, maxDelayNanos), jitterFactor)), rps, eps);
return new RetryPolicy<>(retryPredicate, maxExceptionChain);
}
@CheckReturnValue
public AsyncRetryExecutor buildAsync() {
return buildAsync(DefaultFailSafeExecutor.instance());
}
@CheckReturnValue
public AsyncRetryExecutor buildAsync(final FailSafeExecutor es) {
return build().async(es);
}
}
/**
* Create a retry policy builder.
*
* @param the Type returned by the retried callables.
* @param the type of the Callable's returned.
* @return
*/
@CheckReturnValue
public static > Builder newBuilder() {
return new Builder<>();
}
/**
* Create a retry policy builder copy.
*
* @param the Type returned by the retried callables.
* @param the type of the Callable's returned.
* @return
*/
@CheckReturnValue
public static > Builder newBuilder(final Builder builder) {
return new Builder<>(builder);
}
}