Использование com.google.api.client.util.ExponentialBackOff для реализации общей политики повторных попыток Http
Я пытаюсь реализовать своего рода обработчик, который может факторизовать использование экспоненциального отката для http-запросов, в смысле: "если код состояния удовлетворяет некоторому условию (например, отличается от 200 и 404), повторите вызов".
Вот то, чего я достиг до сих пор, но это кажется слишком сложным, я думаю, что есть более простой способ реализовать это:
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.api.client.util.ExponentialBackOff;
public class HttpExponentialBackoffHandler<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpExponentialBackoffHandler.class);
private ExponentialBackOff expBackoff;
private HttpExponentialBackoffCallback<T> doOperation;
public HttpExponentialBackoffHandler(int intervalMillis, HttpExponentialBackoffCallback<T> doOperation) {
this.expBackoff = new ExponentialBackOff.Builder()
.setInitialIntervalMillis(intervalMillis)
.build();
this.doOperation = doOperation;
}
public T execute() {
int i = 1;
long backOffMillis = ExponentialBackOff.STOP;
HttpExponentialBackoffHandler<T>.HttpOperationResult result = null;
do {
LOGGER.debug("Executing {}° request", i);
result = doOperation.doOperation();
if(doOperation.retry(result.statusCode)) {
try {
backOffMillis = expBackoff.nextBackOffMillis();
if(backOffMillis>0) {
LOGGER.debug("Going to sleep for {}", backOffMillis);
Thread.sleep(backOffMillis);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
i++;
}
while(backOffMillis!=ExponentialBackOff.STOP);
return result.result;
}
public interface HttpExponentialBackoffCallback<T> {
public HttpExponentialBackoffHandler<T>.HttpOperationResult doOperation();
public boolean retry(int httpResponseStatusCode);
}
public class HttpOperationResult {
public T result;
public int statusCode;
public HttpOperationResult(T result, int statusCode) {
super();
this.result = result;
this.statusCode = statusCode;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
}
}
Пример использования:
final GetPublicationDataResponse response = null;
HttpExponentialBackoffHandler<GetPublicationDataResponse> backoffHandler = new HttpExponentialBackoffHandler<GetPublicationDataResponse>(3000, new HttpExponentialBackoffCallback<GetPublicationDataResponse>() {
@SuppressWarnings("rawtypes")
@Override
public HttpExponentialBackoffHandler<GetPublicationDataResponse>.HttpOperationResult doOperation() {
GetPublicationDataResponse response = null;
HttpURLConnection conn = null;
try {
// do the call here
...
if (conn.getResponseCode() == 200) {
response = configService.getObjectMapper().readValue(conn.getInputStream(), GetPublicationDataResponse.class);
}
} catch(IOException e) {
throw new RuntimeException(e);
}
return new HttpOperationResult(response, conn.getResponseCode());
}
@Override
public boolean retry(int httpResponseStatusCode) {
boolean result = true;
if(httpResponseStatusCode==200 || httpResponseStatusCode==404) {
result = false;
}
return true;
}
});
response = backoffHandler.execute();
return response.getPublicationData();
NB. Я не использую HttpRequest от Google, который уже поддерживает этот механизм.
Есть ли у вас идеи улучшить и реорганизовать этот код, чтобы сделать его проще?