com.rt.storage.api.client.http.HttpBackOffUnsuccessfulResponseHandler Maven / Gradle / Ivy
package com.rt.storage.api.client.http;
import com.rt.storage.api.client.util.BackOff;
import com.rt.storage.api.client.util.BackOffUtils;
import com.rt.storage.api.client.util.Beta;
import com.rt.storage.api.client.util.Preconditions;
import com.rt.storage.api.client.util.Sleeper;
import java.io.IOException;
/**
* {@link Beta}
* Back-off handler which handles an abnormal HTTP response with {@link BackOff}.
*
* It is designed to work with only one {@link HttpRequest} at a time. As a result you MUST
* create a new instance of {@link HttpBackOffUnsuccessfulResponseHandler} with a new instance of
* {@link BackOff} for each instance of {@link HttpRequest}.
*
*
Sample usage:
*
*
* request.setUnsuccessfulResponseHandler(
* new HttpBackOffUnsuccessfulResponseHandler(new ExponentialBackOff()));
*
*
* Note: Implementation doesn't call {@link BackOff#reset} at all, since it expects a new {@link
* BackOff} instance.
*
*
Implementation is not thread-safe
*
* @author Eyal Peled
* @since 1.15
*/
@Beta
public class HttpBackOffUnsuccessfulResponseHandler implements HttpUnsuccessfulResponseHandler {
/** Back-off policy. */
private final BackOff backOff;
/** Defines if back-off is required based on an abnormal HTTP response. */
private BackOffRequired backOffRequired = BackOffRequired.ON_SERVER_ERROR;
/** Sleeper. */
private Sleeper sleeper = Sleeper.DEFAULT;
/**
* Constructs a new instance from a {@link BackOff}.
*
* @param backOff back-off policy
*/
public HttpBackOffUnsuccessfulResponseHandler(BackOff backOff) {
this.backOff = Preconditions.checkNotNull(backOff);
}
/** Returns the back-off. */
public final BackOff getBackOff() {
return backOff;
}
/**
* Returns the {@link BackOffRequired} instance which determines if back-off is required based on
* an abnormal HTTP response.
*/
public final BackOffRequired getBackOffRequired() {
return backOffRequired;
}
/**
* Sets the {@link BackOffRequired} instance which determines if back-off is required based on an
* abnormal HTTP response.
*
*
The default value is {@link BackOffRequired#ON_SERVER_ERROR}.
*
*
Overriding is only supported for the purpose of calling the super implementation and
* changing the return type, but nothing else.
*/
public HttpBackOffUnsuccessfulResponseHandler setBackOffRequired(
BackOffRequired backOffRequired) {
this.backOffRequired = Preconditions.checkNotNull(backOffRequired);
return this;
}
/** Returns the sleeper. */
public final Sleeper getSleeper() {
return sleeper;
}
/**
* Sets the sleeper.
*
*
The default value is {@link Sleeper#DEFAULT}.
*
*
Overriding is only supported for the purpose of calling the super implementation and
* changing the return type, but nothing else.
*/
public HttpBackOffUnsuccessfulResponseHandler setSleeper(Sleeper sleeper) {
this.sleeper = Preconditions.checkNotNull(sleeper);
return this;
}
/**
* {@inheritDoc}
*
*
Handles the request with {@link BackOff}. That means that if back-off is required a call to
* {@link Sleeper#sleep(long)} will be made.
*/
@Override
public boolean handleResponse(HttpRequest request, HttpResponse response, boolean supportsRetry)
throws IOException {
if (!supportsRetry) {
return false;
}
// check if back-off is required for this response
if (backOffRequired.isRequired(response)) {
try {
return BackOffUtils.next(sleeper, backOff);
} catch (InterruptedException exception) {
// Mark thread as interrupted since we cannot throw InterruptedException here.
Thread.currentThread().interrupt();
}
}
return false;
}
/**
* {@link Beta}
* Interface which defines if back-off is required based on an abnormal {@link HttpResponse}.
*
* @author Eyal Peled
*/
@Beta
public interface BackOffRequired {
/** Invoked when an abnormal response is received and determines if back-off is required. */
boolean isRequired(HttpResponse response);
/**
* Back-off required implementation which returns {@code true} to every {@link
* #isRequired(HttpResponse)} call.
*/
BackOffRequired ALWAYS =
new BackOffRequired() {
public boolean isRequired(HttpResponse response) {
return true;
}
};
/**
* Back-off required implementation which its {@link #isRequired(HttpResponse)} returns {@code
* true} if a server error occurred (5xx).
*/
BackOffRequired ON_SERVER_ERROR =
new BackOffRequired() {
public boolean isRequired(HttpResponse response) {
return response.getStatusCode() / 100 == 5;
}
};
}
}