ExponentialDelayRetry.java

package fr.sii.ogham.core.retry;

import java.time.Instant;

/**
 * Retry several times with an initial delay to wait after the last execution
 * failure. The following delays are doubled until the maximum attempts is
 * reached.
 * 
 * If maximum attempts are set to five, the initial delay is set to 500ms and
 * the action (named "connect" for the example) takes 100ms to execute before
 * failing, it will result in:
 * 
 * <ul>
 * <li>0: connect</li>
 * <li>100: timeout</li>
 * <li>600: connect</li>
 * <li>700: timeout</li>
 * <li>1700: connect</li>
 * <li>1800: timeout</li>
 * <li>3800: connect</li>
 * <li>3900: timeout</li>
 * <li>7900: connect</li>
 * <li>8000: timeout</li>
 * <li>16000: connect</li>
 * <li>16100: timeout</li>
 * <li>fail</li>
 * </ul>
 * 
 * @author Aurélien Baudet
 *
 */
public class ExponentialDelayRetry implements RetryStrategy {
	private final int maxRetries;
	private final long initialDelay;
	private int retries;
	private int retried;

	/**
	 * Initializes with the maximum attempts and the initial delay to wait after
	 * a failure.
	 * 
	 * @param maxRetries
	 *            the maximum attempts
	 * @param initialDelay
	 *            the initial delay that will be doubled for each attempt
	 */
	public ExponentialDelayRetry(int maxRetries, long initialDelay) {
		super();
		this.maxRetries = maxRetries;
		this.initialDelay = initialDelay;
		retries = maxRetries;
	}

	@Override
	public boolean terminated() {
		return retries <= 0;
	}

	@Override
	public Instant nextDate(Instant executionStartTime, Instant executionFailureTime) {
		retries--;
		long delay = (long) Math.scalb(initialDelay, retried);
		retried++;
		return executionFailureTime.plusMillis(delay);
	}

	public int getRemainingRetries() {
		return retries;
	}

	public int getMaxRetries() {
		return maxRetries;
	}
}