All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lightstep.tracer.retry.RetryPolicy Maven / Gradle / Ivy

package com.lightstep.tracer.retry;

import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A policy that defines the conditions and timing of when retries should be
 * performed.
 * 

* The {@link #retryOn(Exception)} method specifies the exception conditions of * when a retry should occur. *

* The {@link #run(Retryable)} method is the entrypoint for a {@link Retryable} * object to be executed. */ public abstract class RetryPolicy implements Serializable { private static final long serialVersionUID = -8480057566592276543L; private static final Logger logger = LoggerFactory.getLogger(RetryPolicy.class); private final int maxRetries; private final double jitter; /** * Creates a new {@link RetryPolicy} with the specified {@code maxRetries} * value. * * @param maxRetries A positive value representing the number of retry * attempts allowed by the {@link RetryPolicy}. * @param jitter The factor multiplier to be applied to * {@link #getDelayMs(int)} to thereafter be added to the delay for * each retry. * @throws IllegalArgumentException If {@code maxRetries} or {@code jitter} is * negative. */ public RetryPolicy(final int maxRetries, final double jitter) { if (maxRetries < 0) throw new IllegalArgumentException("maxRetries (" + maxRetries + ") is negative"); if (jitter < 0) throw new IllegalArgumentException("jitter (" + jitter + ") is negative"); this.maxRetries = maxRetries; this.jitter = jitter; if (maxRetries <= 0) throw new IllegalArgumentException("maxRetries (" + maxRetries + ") must be a positive value"); } /** * Specifies the exception conditions of when a retry should occur. * * @param e The exception that occurred during execution of a * {@link Retryable} object. * @return {@code true} if a retry should occur, otherwise {@code false}. */ protected boolean retryOn(final Exception e) { return e instanceof RetryException; } /** * The entrypoint for a {@link Retryable} object to be executed. Exceptions in * {@link Retryable#retry(RetryPolicy,int)} will be considered for retry if * the number of {@link #maxRetries} has not been exceeded, and * {@link #retryOn(Exception)} returns {@code true}. * * @param The type of the result object. * @param retryable The {@link Retryable} object to run. * @return The resulting value from {@link Retryable#retry(RetryPolicy,int)}. * @throws RetryFailureException If retry attempts have exceeded * {@link #maxRetries}, or if {@link #retryOn(Exception)} returns * {@code false}. * @throws NullPointerException If {@code retryable} is null. */ public final T run(final Retryable retryable) throws RetryFailureException { return run0(retryable, 0); } /** * The entrypoint for a {@link Retryable} object to be executed. Exceptions in * {@link Retryable#retry(RetryPolicy,int)} will be considered for retry if * the number of {@link #maxRetries} has not been exceeded, and * {@link #retryOn(Exception)} returns {@code true}. * * @param The type of the result object. * @param retryable The {@link Retryable} object to run. * @param timeout The maximum time to retry in milliseconds. * @return The resulting value from {@link Retryable#retry(RetryPolicy,int)}. * @throws RetryFailureException If retry attempts have exceeded * {@link #maxRetries}, if {@link #retryOn(Exception)} returns * {@code false}, or if {@code timeout} is exceeded. * @throws IllegalArgumentException If {@code timeout} is negative. * @throws NullPointerException If the value of {@code timeout} is negative. */ public final T run(final Retryable retryable, final long timeout) throws RetryFailureException { if (timeout < 0) throw new IllegalArgumentException("timeout value (" + timeout + ") is negative"); return run0(retryable, timeout); } private final T run0(final Retryable retryable, final long timeout) throws RetryFailureException { final long startTime = System.currentTimeMillis(); long runTime = 0; for (int attemptNo = 1;; ++attemptNo) { try { return retryable.retry(this, attemptNo); } catch (final RetryFailureException e) { throw e; } catch (final Exception e) { if (attemptNo > maxRetries || !retryOn(e)) throw new RetryFailureException(e, attemptNo, getDelayMs(attemptNo - 1)); long delayMs = getDelayMs(attemptNo); if (jitter > 0) delayMs *= jitter * Math.random() + 1; if (timeout > 0) { final long remaining = timeout - runTime; if (remaining <= 0) throw new RetryFailureException(attemptNo, delayMs); if (remaining < delayMs) delayMs = remaining; } try { Thread.sleep(delayMs); runTime = System.currentTimeMillis() - startTime; } catch (final InterruptedException ie) { throw new RetryFailureException(ie, attemptNo, delayMs); } } if (logger.isDebugEnabled()) logger.debug("Retrying attemptNo = " + attemptNo + ", runTime = " + runTime); } } /** * Returns the number of retry attempts allowed by this {@link RetryPolicy}. * * @return The number of retry attempts allowed by this {@link RetryPolicy}. */ public int getMaxRetries() { return this.maxRetries; } /** * Returns the delay in milliseconds for the specified attempt number. This * method is intended to be implemented by a subclass to define the backoff * function for retry attempts. * * @param attemptNo The attempt number, starting with {@code 1}. * @return The delay in milliseconds for the specified attempt number. */ public abstract long getDelayMs(int attemptNo); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy