/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.core.retrier;
import com.torodb.common.util.RetryHelper.ExceptionHandler;
import com.torodb.core.exceptions.user.UserException;
import com.torodb.core.transaction.RollbackException;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import javax.annotation.concurrent.ThreadSafe;
/**
*
*/
@ThreadSafe
@SuppressWarnings("checkstyle:OverloadMethodsDeclarationOrder")
public interface Retrier {
/**
* Executes the callable until it finished correctly, a runtime exception different than
* {@link RollbackException} is thrown or the replier policy decides to give up.
*
* @param <R>
* @param callable
* @param hints
* @return the value returned by the callable on succeful executions
* @throws RetrierGiveUpException if the policy decides to give up
* @throws RuntimeException if the callable thrown a runtime exception that is not a
* RollbackException, that exception is rethrown
*/
public <R> R retry(Callable<R> callable, EnumSet<Hint> hints)
throws RetrierGiveUpException;
/**
* Executes the callable until it finished correctly, a runtime exception different than
* {@link RollbackException} is thrown, a {@link UserException} is thrown or the replier policy
* decides to give up.
*
* @param <R>
* @param callable the task to be done
* @param hints
* @return the value returned by the callable on succeful executions
* @throws RetrierGiveUpException if the policy decides to give up
* @throws RuntimeException if the callable thrown a runtime exception that is not a
* RollbackException, that exception is rethrown
* @throws UserException if the callable thrown a user exception, that exception is
* rethrown
*/
public <R> R retryOrUserEx(Callable<R> callable, EnumSet<Hint> hints) throws
UserException,
RetrierGiveUpException, RuntimeException;
/**
* Executes the callable until it finished correctly, a runtime exception different than
* {@link RollbackException} is thrown or the replier policy decides to give up, in which case
* returns the value returned by the given supplier.
*
* @param <R>
* @param callable the task to be done
* @param defaultValueSupplier a supplier whose value will be returned if the replier gives up.
* @param hints
* @return the value returned by the callable on succesfull executions or the value returned by
* the supplier if the retrier gives up
* @throws RuntimeException if the callable thrown a runtime exception that is not a
* RollbackException, that exception is rethrown
*/
public <R> R retry(Callable<R> callable, Supplier<R> defaultValueSupplier,
EnumSet<Hint> hints) throws RuntimeException;
/**
* Executes the callable until it finished correctly, a runtime exception different than
* {@link RollbackException} is thrown or the replier policy decides to give up, in which case it
* delegates on the given {@link ExceptionHandler}.
*
* @param <R>
* @param <T> The kind of exception the given handler can throw
* @param callable the task to be done
* @param handler The handler that will be used to handler checked or rollback exceptions once
* the replier gives up.
* @param hints
* @return the value returned by the callable on succesfull executions
* @throws T When the replier gives up and the given handler decides to throw it.
* @throws RuntimeException if the callable thrown a runtime exception that is not a
* RollbackException, that exception is rethrown
*/
public <R, T extends Exception> R retry(Callable<R> callable,
ExceptionHandler<R, T> handler, EnumSet<Hint> hints)
throws T, RuntimeException;
/**
* @see #retry(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable) throws RetrierGiveUpException,
RetrierAbortException {
return retry(callable, EnumSet.noneOf(Hint.class));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable, Hint hint) throws
RetrierGiveUpException, RetrierAbortException {
return retry(callable, EnumSet.of(hint));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable, Hint hint1, Hint hint2) throws
RetrierGiveUpException, RetrierAbortException {
return retry(callable, EnumSet.of(hint1, hint2));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable, Hint hint1, Hint hint2, Hint hint3)
throws RetrierGiveUpException, RetrierAbortException {
return retry(callable, EnumSet.of(hint1, hint2, hint3));
}
/**
* @see #retryOrUserEx(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retryOrUserEx(Callable<R> callable) throws UserException,
RetrierGiveUpException, RetrierAbortException {
return retryOrUserEx(callable, EnumSet.noneOf(Hint.class));
}
/**
* @see #retryOrUserEx(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retryOrUserEx(Callable<R> callable, Hint hint) throws
UserException,
RetrierGiveUpException, RetrierAbortException {
return retryOrUserEx(callable, EnumSet.of(hint));
}
/**
* @see #retryOrUserEx(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retryOrUserEx(Callable<R> callable, Hint hint1, Hint hint2)
throws UserException,
RetrierGiveUpException, RetrierAbortException {
return retryOrUserEx(callable, EnumSet.of(hint1, hint2));
}
/**
* @see #retryOrUserEx(java.util.concurrent.Callable, java.util.EnumSet)
*/
public default <R> R retryOrUserEx(Callable<R> callable, Hint hint1, Hint hint2,
Hint hint3) throws UserException,
RetrierGiveUpException, RetrierAbortException {
return retryOrUserEx(callable, EnumSet.of(hint1, hint2, hint3));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.function.Supplier, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable,
Supplier<R> defaultValueSupplier) {
return retry(callable, defaultValueSupplier, EnumSet.noneOf(Hint.class));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.function.Supplier, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable,
Supplier<R> defaultValueSupplier, Hint hint) {
return retry(callable, defaultValueSupplier, EnumSet.of(hint));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.function.Supplier, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable,
Supplier<R> defaultValueSupplier, Hint hint1, Hint hint2) {
return retry(callable, defaultValueSupplier, EnumSet.of(hint1, hint2));
}
/**
* @see #retry(java.util.concurrent.Callable, java.util.function.Supplier, java.util.EnumSet)
*/
public default <R> R retry(Callable<R> callable,
Supplier<R> defaultValueSupplier, Hint hint1, Hint hint2, Hint hint3) {
return retry(callable, defaultValueSupplier, EnumSet.of(hint1, hint2, hint3));
}
/**
* @see #retry(java.util.concurrent.Callable, com.torodb.common.util.RetryHelper.ExceptionHandler,
* java.util.EnumSet)
*/
public default <R, T extends Exception> R retry(Callable<R> callable,
ExceptionHandler<R, T> handler) throws T {
return retry(callable, handler, EnumSet.noneOf(Hint.class));
}
/**
* @see #retry(java.util.concurrent.Callable, com.torodb.common.util.RetryHelper.ExceptionHandler,
* java.util.EnumSet)
*/
public default <R, T extends Exception> R retry(Callable<R> callable,
ExceptionHandler<R, T> handler, Hint hint) throws T {
return retry(callable, handler, EnumSet.of(hint));
}
/**
* @see #retry(java.util.concurrent.Callable, com.torodb.common.util.RetryHelper.ExceptionHandler,
* java.util.EnumSet)
*/
public default <R, T extends Exception> R retry(Callable<R> callable,
ExceptionHandler<R, T> handler, Hint hint1, Hint hint2) throws T {
return retry(callable, handler, EnumSet.of(hint1, hint2));
}
/**
* @see #retry(java.util.concurrent.Callable, com.torodb.common.util.RetryHelper.ExceptionHandler,
* java.util.EnumSet)
*/
public default <R, T extends Exception> R retry(Callable<R> callable,
ExceptionHandler<R, T> handler, Hint hint1, Hint hint2, Hint hint3) throws T {
return retry(callable, handler, EnumSet.of(hint1, hint2, hint3));
}
public static enum Hint {
/**
* For task that it is critical to be executed.
* <p>
* This hint indicates that the retrier should try to execute the task more times before it
* gives up when rollbacks are recived, because once it does, ToroDB could become unestable or
* at least it will be difficult or expensive to recover. The retrier could even decide to never
* give up when this hint is sent.
*/
CRITICAL,
/**
* For task that usually recives rollbacks.
* <p>
* This hint indicates that the retrier should try to execute the task more times before it
* gives up when rollbacks are recived.
*/
FREQUENT_ROLLBACK,
/**
* For task that do not usually recives rollbacks.
* <p>
* This hint indicates that the retrier should try to execute the task less times before it
* gives up when rollbacks are recived.
*/
INFREQUENT_ROLLBACK,
/**
* For task whose rollbacks can be usually be reduced if the next attempt is done after waiting
* a short amount of time.
*/
TIME_SENSIBLE
}
}