JustRetryStrategy.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.strategy;
import static hera.util.ValidationUtils.assertTrue;
import static org.slf4j.LoggerFactory.getLogger;
import hera.api.function.Function;
import hera.api.function.Function0;
import hera.api.function.Functions;
import hera.api.model.internal.Time;
import hera.exception.DecoratorChainException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.slf4j.Logger;
@ToString(exclude = "logger")
@EqualsAndHashCode(callSuper = false)
public class JustRetryStrategy extends FailoverStrategy {
public static final int DEFAULT_RETRY_COUNT = 1;
public static final long DEFAULT_RETRY_INTERVAL = 500L; // milliseconds
protected final Logger logger = getLogger(getClass());
protected final int count;
protected final long interval; // milliseconds
public JustRetryStrategy(final int count) {
this(count, Time.of(DEFAULT_RETRY_INTERVAL, TimeUnit.MILLISECONDS));
}
/**
* {@code RetryStrategy} constructor.
*
* @param count retry count. must be positive
* @param interval retry interval
*/
public JustRetryStrategy(final int count, final Time interval) {
assertTrue(0 < count, "Retry count must be positive");
this.count = count;
this.interval = interval.toMilliseconds();
}
@Override
protected <R> R onFailure(final Exception e, final Function<R> f, final List<Object> args) {
logger.debug("First attempt failed with {}", extractExactCause(e).toString());
R ret = null;
final Function0<R> invocation = Functions.buildInvocation(f, args);
Exception recentException = null;
int countDown = this.count;
boolean success = false;
while (0 < countDown && !success) {
try {
// wait
--countDown;
Thread.sleep(this.interval);
// try
ret = invocation.apply();
success = true;
} catch (Exception retryError) {
recentException = retryError;
logger.info(
"Retry failed.. retry with same args after {} milliseconds (try left: {}) cause: {}",
this.interval, countDown, extractExactCause(retryError).toString());
}
}
// failed even retry
if (null == ret) {
throw new DecoratorChainException(recentException);
}
return ret;
}
protected Throwable extractExactCause(final Exception e) {
return (e instanceof DecoratorChainException) ? e.getCause() : e;
}
}