
co.elastic.clients.transport.BackoffPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.servicemix.bundles.elasticsearch-java
Show all versions of org.apache.servicemix.bundles.elasticsearch-java
This OSGi bundle wraps ${pkgArtifactId} ${pkgVersion} jar files.
The newest version!
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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 co.elastic.clients.transport;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Provides a set of generic backoff policies. Backoff policies are used to calculate the number of times an action will be retried
* and the intervals between those retries.
*
* Notes for implementing custom subclasses:
*
* The underlying mathematical principle of BackoffPolicy
are progressions which can be either finite or infinite although
* the latter should not be used for retrying. A progression can be mapped to a java.util.Iterator
with the following
* semantics:
*
*
* #hasNext()
determines whether the progression has more elements. Return true
for infinite progressions
*
* #next()
determines the next element in the progression, i.e. the next wait time period
*
*
* Note that backoff policies are exposed as Iterables
in order to be consumed multiple times.
*/
public abstract class BackoffPolicy implements Iterable {
private static final BackoffPolicy NO_BACKOFF = new NoBackoff();
/**
* Creates a backoff policy that will not allow any backoff, i.e. an operation will fail after the first attempt.
*
* @return A backoff policy without any backoff period. The returned instance is thread safe.
*/
public static BackoffPolicy noBackoff() {
return NO_BACKOFF;
}
/**
* Creates an new constant backoff policy with the provided configuration.
*
* @param delay The delay defines how long to wait between retry attempts. Must not be null.
* Must be <= Integer.MAX_VALUE
ms.
* @param maxNumberOfRetries The maximum number of retries. Must be a non-negative number.
* @return A backoff policy with a constant wait time between retries. The returned instance is thread safe but each
* iterator created from it should only be used by a single thread.
*/
public static BackoffPolicy constantBackoff(Long delay, int maxNumberOfRetries) {
return new ConstantBackoff(checkDelay(delay), maxNumberOfRetries);
}
/**
* Creates an new exponential backoff policy with a default configuration of 50 ms initial wait period and 8 retries taking
* roughly 5.1 seconds in total.
*
* @return A backoff policy with an exponential increase in wait time for retries. The returned instance is thread safe but each
* iterator created from it should only be used by a single thread.
*/
public static BackoffPolicy exponentialBackoff() {
return exponentialBackoff(50L, 8);
}
/**
* Creates an new exponential backoff policy with the provided configuration.
*
* @param initialDelay The initial delay defines how long to wait for the first retry attempt. Must not be null.
* Must be <= Integer.MAX_VALUE
ms.
* @param maxNumberOfRetries The maximum number of retries. Must be a non-negative number.
* @return A backoff policy with an exponential increase in wait time for retries. The returned instance is thread safe but each
* iterator created from it should only be used by a single thread.
*/
public static BackoffPolicy exponentialBackoff(Long initialDelay, int maxNumberOfRetries) {
return new ExponentialBackoff(checkDelay(initialDelay), maxNumberOfRetries);
}
/**
* Creates a new linear backoff policy with the provided configuration
*
* @param delayIncrement The amount by which to increment the delay on each retry
* @param maxNumberOfRetries The maximum number of retries
* @param maximumDelay The maximum delay
* @return A backoff policy with linear increase in wait time for retries.
*/
public static BackoffPolicy linearBackoff(Long delayIncrement, int maxNumberOfRetries, Long maximumDelay) {
return new LinearBackoff(delayIncrement, maxNumberOfRetries, maximumDelay);
}
/**
* Wraps the backoff policy in one that calls a method every time a new backoff is taken from the policy.
*/
public static BackoffPolicy wrap(BackoffPolicy delegate, Runnable onBackoff) {
return new WrappedBackoffPolicy(delegate, onBackoff);
}
private static Long checkDelay(Long delay) {
if (delay > Integer.MAX_VALUE) {
throw new IllegalArgumentException("delay must be <= " + Integer.MAX_VALUE + " ms");
}
return delay;
}
private static class NoBackoff extends BackoffPolicy {
@Override
public Iterator iterator() {
return Collections.emptyIterator();
}
@Override
public String toString() {
return "NoBackoff";
}
}
private static class ExponentialBackoff extends BackoffPolicy {
private final Long start;
private final int numberOfElements;
private ExponentialBackoff(Long start, int numberOfElements) {
assert start >= 0;
assert numberOfElements >= 0;
this.start = start;
this.numberOfElements = numberOfElements;
}
@Override
public Iterator iterator() {
return new ExponentialBackoffIterator(start, numberOfElements);
}
@Override
public String toString() {
return "ExponentialBackoff{start=" + start + ", numberOfElements=" + numberOfElements + '}';
}
}
private static class ExponentialBackoffIterator implements Iterator {
private final int numberOfElements;
private final Long start;
private int currentlyConsumed;
private ExponentialBackoffIterator(Long start, int numberOfElements) {
this.start = start;
this.numberOfElements = numberOfElements;
}
@Override
public boolean hasNext() {
return currentlyConsumed < numberOfElements;
}
@Override
public Long next() {
if (!hasNext()) {
throw new NoSuchElementException("Only up to " + numberOfElements + " elements");
}
Long result = start + 10L * ((int) Math.exp(0.8d * (currentlyConsumed)) - 1);
currentlyConsumed++;
return result;
}
}
private static final class ConstantBackoff extends BackoffPolicy {
private final Long delay;
private final int numberOfElements;
ConstantBackoff(Long delay, int numberOfElements) {
assert numberOfElements >= 0;
this.delay = delay;
this.numberOfElements = numberOfElements;
}
@Override
public Iterator iterator() {
return new ConstantBackoffIterator(delay, numberOfElements);
}
@Override
public String toString() {
return "ConstantBackoff{delay=" + delay + ", numberOfElements=" + numberOfElements + '}';
}
}
private static final class ConstantBackoffIterator implements Iterator {
private final Long delay;
private final int numberOfElements;
private int curr;
ConstantBackoffIterator(Long delay, int numberOfElements) {
this.delay = delay;
this.numberOfElements = numberOfElements;
}
@Override
public boolean hasNext() {
return curr < numberOfElements;
}
@Override
public Long next() {
if (hasNext() == false) {
throw new NoSuchElementException();
}
curr++;
return delay;
}
}
private static final class WrappedBackoffPolicy extends BackoffPolicy {
private final BackoffPolicy delegate;
private final Runnable onBackoff;
WrappedBackoffPolicy(BackoffPolicy delegate, Runnable onBackoff) {
this.delegate = delegate;
this.onBackoff = onBackoff;
}
@Override
public Iterator iterator() {
return new WrappedBackoffIterator(delegate.iterator(), onBackoff);
}
@Override
public String toString() {
return "WrappedBackoffPolicy{delegate=" + delegate + ", onBackoff=" + onBackoff + '}';
}
}
private static final class WrappedBackoffIterator implements Iterator {
private final Iterator delegate;
private final Runnable onBackoff;
WrappedBackoffIterator(Iterator delegate, Runnable onBackoff) {
this.delegate = delegate;
this.onBackoff = onBackoff;
}
@Override
public boolean hasNext() {
return delegate.hasNext();
}
@Override
public Long next() {
if (false == delegate.hasNext()) {
throw new NoSuchElementException();
}
onBackoff.run();
return delegate.next();
}
}
private static final class LinearBackoff extends BackoffPolicy {
private final Long delayIncrement;
private final int maxNumberOfRetries;
private final Long maximumDelay;
private LinearBackoff(Long delayIncrement, int maxNumberOfRetries, @Nullable Long maximumDelay) {
this.delayIncrement = delayIncrement;
this.maxNumberOfRetries = maxNumberOfRetries;
this.maximumDelay = maximumDelay;
}
@Override
public Iterator iterator() {
return new LinearBackoffIterator(delayIncrement, maxNumberOfRetries, maximumDelay);
}
@Override
public String toString() {
return "LinearBackoff{"
+ "delayIncrement="
+ delayIncrement
+ ", maxNumberOfRetries="
+ maxNumberOfRetries
+ ", maximumDelay="
+ maximumDelay
+ '}';
}
}
private static final class LinearBackoffIterator implements Iterator {
private final Long delayIncrement;
private final int maxNumberOfRetries;
private final Long maximumDelay;
private int curr;
private LinearBackoffIterator(Long delayIncrement, int maxNumberOfRetries, @Nullable Long maximumDelay) {
this.delayIncrement = delayIncrement;
this.maxNumberOfRetries = maxNumberOfRetries;
this.maximumDelay = maximumDelay;
}
@Override
public boolean hasNext() {
return curr < maxNumberOfRetries;
}
@Override
public Long next() {
curr++;
Long Long = curr * delayIncrement;
return maximumDelay == null ? Long : Long.compareTo(maximumDelay) < 0 ? Long : maximumDelay;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy