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
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -126,14 +126,20 @@ public abstract class FutureCommandConnectionPool<C, O extends FutureCommand<?,
|
|||
return handle;
|
||||
}
|
||||
|
||||
protected void resubmitCommand(C connection) {
|
||||
protected void resubmitIfRequestIsReplayable(C connection, Exception e) {
|
||||
O command = getCommandFromConnection(connection);
|
||||
if (command != null) {
|
||||
logger.info("resubmitting command: %1s", command);
|
||||
commandQueue.add(command);
|
||||
if (isReplayable(command)) {
|
||||
logger.info("resubmitting command: %1s", command);
|
||||
commandQueue.add(command);
|
||||
} else {
|
||||
command.setException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isReplayable(O command);
|
||||
|
||||
O getCommandFromConnection(C connection) {
|
||||
FutureCommandConnectionHandle<C, O> handle = getHandleFromConnection(connection);
|
||||
if (handle != null && handle.getCommand() != null) {
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.jclouds.logging.Logger;
|
|||
*/
|
||||
public class HttpFutureCommand<T> extends
|
||||
FutureCommand<HttpRequest, HttpResponse, T> {
|
||||
|
||||
public HttpFutureCommand(String method, String uri,
|
||||
ResponseCallable<T> responseCallable) {
|
||||
super(new HttpRequest(checkNotNull(method, "method"), checkNotNull(uri,
|
||||
|
@ -73,4 +74,5 @@ public class HttpFutureCommand<T> extends
|
|||
this.response = response;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,8 +25,13 @@ package org.jclouds.http;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
|
@ -44,6 +49,9 @@ public class HttpRequest {
|
|||
String contentType;
|
||||
long contentLength = -1;
|
||||
|
||||
@Resource
|
||||
protected Logger logger = Logger.NULL;
|
||||
|
||||
public HttpRequest(String method, String uri) {
|
||||
this.method = checkNotNull(method, "method");
|
||||
this.uri = checkNotNull(uri, "uri");
|
||||
|
@ -87,6 +95,15 @@ public class HttpRequest {
|
|||
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() {
|
||||
return content;
|
||||
}
|
||||
|
@ -110,7 +127,7 @@ public class HttpRequest {
|
|||
public void setContentLength(long contentLength) {
|
||||
this.contentLength = contentLength;
|
||||
}
|
||||
|
||||
|
||||
public String getFirstHeaderOrNull(String string) {
|
||||
Collection<String> values = headers.get(string);
|
||||
return (values != null && values.size() >= 1) ? values.iterator()
|
||||
|
|
|
@ -70,26 +70,47 @@ public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
|
|||
this.target = target;
|
||||
}
|
||||
|
||||
public void submit(HttpFutureCommand<?> operation) {
|
||||
HttpRequest request = (HttpRequest) operation.getRequest();
|
||||
public void submit(HttpFutureCommand<?> command) {
|
||||
HttpRequest request = (HttpRequest) command.getRequest();
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
for (HttpRequestFilter filter : getRequestFilters()) {
|
||||
filter.filter(request);
|
||||
}
|
||||
logger.trace("%1s - converting request %2s", target, request);
|
||||
connection = openJavaConnection(request);
|
||||
logger.trace("%1s - submitting request %2s", target, connection);
|
||||
HttpResponse response = getResponse(connection);
|
||||
logger.trace("%1s - received response %2s", target, response);
|
||||
|
||||
operation.getResponseFuture().setResponse(response);
|
||||
operation.getResponseFuture().run();
|
||||
HttpResponse response = null;
|
||||
for (;;) {
|
||||
try {
|
||||
logger.trace("%1s - converting request %2s", target,
|
||||
request);
|
||||
connection = openJavaConnection(request);
|
||||
logger.trace("%1s - submitting request %2s", target,
|
||||
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) {
|
||||
HttpResponse response = new HttpResponse();
|
||||
response.setStatusCode(404);
|
||||
operation.getResponseFuture().setResponse(response);
|
||||
operation.getResponseFuture().run();
|
||||
command.getResponseFuture().setResponse(response);
|
||||
command.getResponseFuture().run();
|
||||
} catch (Exception e) {
|
||||
if (connection != null) {
|
||||
StringBuilder errors = new StringBuilder();
|
||||
|
@ -108,7 +129,7 @@ public class JavaUrlHttpFutureCommandClient implements HttpFutureCommandClient {
|
|||
} catch (IOException e2) {
|
||||
}
|
||||
}
|
||||
operation.setException(e);
|
||||
command.setException(e);
|
||||
} finally {
|
||||
// DO NOT disconnect, as it will also close the unconsumed
|
||||
// outputStream from above.
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Properties;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -81,6 +82,8 @@ public abstract class BaseHttpFutureCommandClientTest {
|
|||
public void setUpJetty(@Optional("8123") final int testPort)
|
||||
throws Exception {
|
||||
Handler handler = new AbstractHandler() {
|
||||
private AtomicInteger cycle = new AtomicInteger(0);
|
||||
|
||||
public void handle(String target, HttpServletRequest request,
|
||||
HttpServletResponse response, int dispatch)
|
||||
throws IOException, ServletException {
|
||||
|
@ -89,12 +92,24 @@ public abstract class BaseHttpFutureCommandClientTest {
|
|||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().println("test");
|
||||
} else {
|
||||
if (failEveryTenRequests(request, response))
|
||||
return;
|
||||
response.setContentType("text/xml");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().println(XML);
|
||||
}
|
||||
((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);
|
||||
|
|
Loading…
Reference in New Issue