package org.zalando.catwatch.backend.scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component;
import org.zalando.catwatch.backend.mail.MailSender;
import java.util.HashMap;
import java.util.Map;
/**
* Tries to fetch organizations data from GitHub and saves it to the database.
*/
@Component
public class RetryableFetcher {
private final Fetcher fetcher;
private final int maxAttempts;
private final int initialInterval;
private final int maxInterval;
private final double multiplier;
private final MailSender mailSender;
@Autowired
public RetryableFetcher(Fetcher fetcher,
@Value("${fetcher.maxAttempts}") int maxAttempts,
@Value("${fetcher.initialInterval}") int initialInterval,
@Value("${fetcher.maxInterval}") int maxInterval,
@Value("${fetcher.multiplier}") double multiplier,
MailSender mailSender) {
this.fetcher = fetcher;
this.maxAttempts = maxAttempts;
this.initialInterval = initialInterval;
this.maxInterval = maxInterval;
this.multiplier = multiplier;
this.mailSender = mailSender;
}
public void tryFetchData() {
RetryCallback<Boolean, RuntimeException> retryCallback = context -> fetcher.fetchData();
RecoveryCallback<Boolean> recoveryCallback = retryContext -> mailSender.send(retryContext.getLastThrowable());
retryTemplate().execute(retryCallback, recoveryCallback);
}
private RetryTemplate retryTemplate() {
RetryTemplate template = new RetryTemplate();
template.setBackOffPolicy(exponentialBackOffPolicy());
template.setRetryPolicy(retryPolicy());
return template;
}
private SimpleRetryPolicy retryPolicy() {
return new SimpleRetryPolicy(maxAttempts, transientExceptions());
}
private ExponentialBackOffPolicy exponentialBackOffPolicy() {
ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
exponentialBackOffPolicy.setInitialInterval(initialInterval);
exponentialBackOffPolicy.setMaxInterval(maxInterval);
exponentialBackOffPolicy.setMultiplier(multiplier);
return exponentialBackOffPolicy;
}
private Map<Class<? extends Throwable>, Boolean> transientExceptions() {
Map<Class<? extends Throwable>, Boolean> exceptions = new HashMap<>();
exceptions.put(CrawlerRetryException.class, true);
return exceptions;
}
}