mirror of https://github.com/apache/jclouds.git
Issue 4: retry on 500
git-svn-id: http://jclouds.googlecode.com/svn/trunk@347 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
7da272ddad
commit
352f99b0b8
|
@ -100,7 +100,7 @@ public class FutureCommand<Q, R, T> implements Future<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName()+"{" + "tCallable=" + callable
|
return getClass().getSimpleName() + "{" + "tCallable=" + callable
|
||||||
+ '}';
|
+ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,4 +138,5 @@ public class FutureCommand<Q, R, T> implements Future<T> {
|
||||||
|
|
||||||
public void setResponse(R response);
|
public void setResponse(R response);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,14 +126,20 @@ public abstract class FutureCommandConnectionPool<C, O extends FutureCommand<?,
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resubmitCommand(C connection) {
|
protected void resubmitIfRequestIsReplayable(C connection, Exception e) {
|
||||||
O command = getCommandFromConnection(connection);
|
O command = getCommandFromConnection(connection);
|
||||||
if (command != null) {
|
if (command != null) {
|
||||||
logger.info("resubmitting command: %1s", command);
|
if (isReplayable(command)) {
|
||||||
commandQueue.add(command);
|
logger.info("resubmitting command: %1s", command);
|
||||||
|
commandQueue.add(command);
|
||||||
|
} else {
|
||||||
|
command.setException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract boolean isReplayable(O command);
|
||||||
|
|
||||||
O getCommandFromConnection(C connection) {
|
O getCommandFromConnection(C connection) {
|
||||||
FutureCommandConnectionHandle<C, O> handle = getHandleFromConnection(connection);
|
FutureCommandConnectionHandle<C, O> handle = getHandleFromConnection(connection);
|
||||||
if (handle != null && handle.getCommand() != null) {
|
if (handle != null && handle.getCommand() != null) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.jclouds.logging.Logger;
|
||||||
*/
|
*/
|
||||||
public class HttpFutureCommand<T> extends
|
public class HttpFutureCommand<T> extends
|
||||||
FutureCommand<HttpRequest, HttpResponse, T> {
|
FutureCommand<HttpRequest, HttpResponse, T> {
|
||||||
|
|
||||||
public HttpFutureCommand(String method, String uri,
|
public HttpFutureCommand(String method, String uri,
|
||||||
ResponseCallable<T> responseCallable) {
|
ResponseCallable<T> responseCallable) {
|
||||||
super(new HttpRequest(checkNotNull(method, "method"), checkNotNull(uri,
|
super(new HttpRequest(checkNotNull(method, "method"), checkNotNull(uri,
|
||||||
|
@ -73,4 +74,5 @@ public class HttpFutureCommand<T> extends
|
||||||
this.response = response;
|
this.response = response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,13 @@ package org.jclouds.http;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
|
@ -44,6 +49,9 @@ public class HttpRequest {
|
||||||
String contentType;
|
String contentType;
|
||||||
long contentLength = -1;
|
long contentLength = -1;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
public HttpRequest(String method, String uri) {
|
public HttpRequest(String method, String uri) {
|
||||||
this.method = checkNotNull(method, "method");
|
this.method = checkNotNull(method, "method");
|
||||||
this.uri = checkNotNull(uri, "uri");
|
this.uri = checkNotNull(uri, "uri");
|
||||||
|
@ -87,6 +95,15 @@ public class HttpRequest {
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isReplayable() {
|
||||||
|
Object content = getContent();
|
||||||
|
if (content != null && content instanceof InputStream) {
|
||||||
|
logger.warn("%1s: InputStreams are not replayable", toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Object getContent() {
|
public Object getContent() {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +127,7 @@ public class HttpRequest {
|
||||||
public void setContentLength(long contentLength) {
|
public void setContentLength(long contentLength) {
|
||||||
this.contentLength = contentLength;
|
this.contentLength = contentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFirstHeaderOrNull(String string) {
|
public String getFirstHeaderOrNull(String string) {
|
||||||
Collection<String> values = headers.get(string);
|
Collection<String> values = headers.get(string);
|
||||||
return (values != null && values.size() >= 1) ? values.iterator()
|
return (values != null && values.size() >= 1) ? values.iterator()
|
||||||
|
|
|
@ -70,26 +70,47 @@ public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void submit(HttpFutureCommand<?> operation) {
|
public void submit(HttpFutureCommand<?> command) {
|
||||||
HttpRequest request = (HttpRequest) operation.getRequest();
|
HttpRequest request = (HttpRequest) command.getRequest();
|
||||||
HttpURLConnection connection = null;
|
HttpURLConnection connection = null;
|
||||||
try {
|
try {
|
||||||
for (HttpRequestFilter filter : getRequestFilters()) {
|
for (HttpRequestFilter filter : getRequestFilters()) {
|
||||||
filter.filter(request);
|
filter.filter(request);
|
||||||
}
|
}
|
||||||
logger.trace("%1s - converting request %2s", target, request);
|
HttpResponse response = null;
|
||||||
connection = openJavaConnection(request);
|
for (;;) {
|
||||||
logger.trace("%1s - submitting request %2s", target, connection);
|
try {
|
||||||
HttpResponse response = getResponse(connection);
|
logger.trace("%1s - converting request %2s", target,
|
||||||
logger.trace("%1s - received response %2s", target, response);
|
request);
|
||||||
|
connection = openJavaConnection(request);
|
||||||
operation.getResponseFuture().setResponse(response);
|
logger.trace("%1s - submitting request %2s", target,
|
||||||
operation.getResponseFuture().run();
|
connection);
|
||||||
|
response = getResponse(connection);
|
||||||
|
logger.trace("%1s - received response %2s", target,
|
||||||
|
response);
|
||||||
|
if (request.isReplayable()
|
||||||
|
&& response.getStatusCode() >= 500) {
|
||||||
|
logger.info("resubmitting command: %1s", command);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (request.isReplayable()
|
||||||
|
&& e.getMessage().indexOf(
|
||||||
|
"Server returned HTTP response code: 5") >= 0) {
|
||||||
|
logger.info("resubmitting command: %1s", command);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
command.getResponseFuture().setResponse(response);
|
||||||
|
command.getResponseFuture().run();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
HttpResponse response = new HttpResponse();
|
HttpResponse response = new HttpResponse();
|
||||||
response.setStatusCode(404);
|
response.setStatusCode(404);
|
||||||
operation.getResponseFuture().setResponse(response);
|
command.getResponseFuture().setResponse(response);
|
||||||
operation.getResponseFuture().run();
|
command.getResponseFuture().run();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
StringBuilder errors = new StringBuilder();
|
StringBuilder errors = new StringBuilder();
|
||||||
|
@ -108,7 +129,7 @@ public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
|
||||||
} catch (IOException e2) {
|
} catch (IOException e2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operation.setException(e);
|
command.setException(e);
|
||||||
} finally {
|
} finally {
|
||||||
// DO NOT disconnect, as it will also close the unconsumed
|
// DO NOT disconnect, as it will also close the unconsumed
|
||||||
// outputStream from above.
|
// outputStream from above.
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Properties;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -81,6 +82,8 @@ public abstract class BaseHttpFutureCommandClientTest {
|
||||||
public void setUpJetty(@Optional("8123") final int testPort)
|
public void setUpJetty(@Optional("8123") final int testPort)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Handler handler = new AbstractHandler() {
|
Handler handler = new AbstractHandler() {
|
||||||
|
private AtomicInteger cycle = new AtomicInteger(0);
|
||||||
|
|
||||||
public void handle(String target, HttpServletRequest request,
|
public void handle(String target, HttpServletRequest request,
|
||||||
HttpServletResponse response, int dispatch)
|
HttpServletResponse response, int dispatch)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
@ -89,12 +92,24 @@ public abstract class BaseHttpFutureCommandClientTest {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
response.getWriter().println("test");
|
response.getWriter().println("test");
|
||||||
} else {
|
} else {
|
||||||
|
if (failEveryTenRequests(request, response))
|
||||||
|
return;
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
response.getWriter().println(XML);
|
response.getWriter().println(XML);
|
||||||
}
|
}
|
||||||
((Request) request).setHandled(true);
|
((Request) request).setHandled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean failEveryTenRequests(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) throws IOException {
|
||||||
|
if (cycle.incrementAndGet() % 10 == 0) {
|
||||||
|
response.sendError(500);
|
||||||
|
((Request) request).setHandled(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new Server(testPort);
|
server = new Server(testPort);
|
||||||
|
|
Loading…
Reference in New Issue