package io.github.resilience4j.retry.internal;
import io.github.resilience4j.retry.AsyncRetry;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.event.RetryEvent;
import io.github.resilience4j.retry.event.RetryOnErrorEvent;
import io.github.resilience4j.retry.event.RetryOnSuccessEvent;
import io.reactivex.Flowable;
import io.reactivex.processors.FlowableProcessor;
import io.reactivex.processors.PublishProcessor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class AsyncRetryContext implements AsyncRetry {
private final String name;
private final int maxAttempts;
private final Function<Integer, Long> intervalFunction;
private final Metrics metrics;
private final FlowableProcessor<RetryEvent> eventPublisher;
private final Predicate<Throwable> exceptionPredicate;
private final AtomicInteger numOfAttempts = new AtomicInteger(0);
public AsyncRetryContext(String name, RetryConfig config) {
this.name = name;
this.maxAttempts = config.getMaxAttempts();
this.intervalFunction = config.getIntervalFunction();
this.exceptionPredicate = config.getExceptionPredicate();
PublishProcessor<RetryEvent> publisher = PublishProcessor.create();
this.eventPublisher = publisher.toSerialized();
this.metrics = this.new AsyncRetryContextMetrics();
}
@Override
public String getName() {
return name;
}
@Override
public void onSuccess() {
int currentNumOfAttempts = numOfAttempts.get();
publishRetryEvent(() -> new RetryOnSuccessEvent(name, currentNumOfAttempts, null));
}
@Override
public long onError(Throwable throwable) {
if (!exceptionPredicate.test(throwable)) {
return -1;
}
int attempt = numOfAttempts.addAndGet(1);
if (attempt > maxAttempts) {
return -1;
}
publishRetryEvent(() -> new RetryOnErrorEvent(name, attempt, throwable));
return intervalFunction.apply(attempt);
}
@Override
public Flowable<RetryEvent> getEventStream() {
return eventPublisher;
}
private void publishRetryEvent(Supplier<RetryEvent> event) {
if(eventPublisher.hasSubscribers()) {
eventPublisher.onNext(event.get());
}
}
/**
* {@inheritDoc}
*/
@Override
public Metrics getMetrics() {
return this.metrics;
}
/**
* {@inheritDoc}
*/
public final class AsyncRetryContextMetrics implements Metrics {
private AsyncRetryContextMetrics() {
}
/**
* @return current number of retry attempts made.
*/
@Override
public int getNumAttempts() {
return numOfAttempts.get();
}
/**
* @return the maximum allowed retries to make.
*/
@Override
public int getMaxAttempts() {
return maxAttempts;
}
}
}