package de.tum.in.www1.jReto.util;
import java.util.concurrent.Executor;
public class RetryableActionExecutor {
/**
* A RetryableAction should encapsulate some action that might fail or succeed after a certain delay. If it fails, or does not succeed in a specified time interval, it can be retried.
* For example, one might try to establish a connection to a server that might not be online. The process should be retried if it fails after a certain amount of time.
*
* You have to notify the RetryableActionExecutor about the success or failure of the action by calling onSuccess() or onFail().
*/
public static interface RetryableAction {
/**
* Runs the RetryableAction.
*
* @param attemptNumber The number of times the action has been attempted.
* */
void run(int attemptNumber);
}
/** The action to executed. */
private final RetryableAction action;
/** The executor that the action is executed on. */
private final Executor executor;
/** The timer settings used to create the timer that triggers a retry. */
private final Timer.BackoffTimerSettings timerSettings;
/** The timer used by the RetryableActionExecutor. */
private Timer timer;
/**
* Constructs a new RetryableActionExecutor.
*
* @param action: The action that should be retried if it does not succeed in time or fails.
* @param timerSettings: Specifies the delay in which the action should be executed.
* @param dispatchQueue: The dispatch queue on which actions should be executed.
*/
public RetryableActionExecutor(RetryableAction action, Timer.BackoffTimerSettings timerSettings, Executor executor) {
this.action = action;
this.timerSettings = timerSettings;
this.executor = executor;
}
/**
* Starts the RetryableActionExecutor. The action is called immediately when calling start. A timer is created with the given settings that retries the action if it does not succeed in time.
*/
public void start() {
if (this.timer != null) return;
this.timer = Timer.repeatWithBackoff(
this.timerSettings.initialDelay,
this.timerSettings.backoffFactor,
this.timerSettings.maximumDelay,
this.executor,
new Timer.Action() {
@Override
public void run(Timer timer, int executionCount) {
RetryableActionExecutor.this.action.run(executionCount + 1);
}
});
RetryableActionExecutor.this.action.run(0);
//this.executor.execute(new Runnable() {
// @Override
// public void run() {
// }
//});
}
/**
* Stops trying to execute the RetryableAction.
*/
public void stop() {
if (this.timer != null) this.timer.stop();
}
/**
* Call this method when the RetryableAction succeeds. This method causes the executor to stop calling the action.
*/
public void onSuccess() {
this.stop();
}
/**
* Call this method when the RetryableAction succeeds. This method causes the executor to stop calling the action.
*/
public void onFail() {
if (this.timer == null) { this.start(); }
}
}