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:
adrian.f.cole 2009-05-05 16:47:17 +00:00
parent 7da272ddad
commit 352f99b0b8
6 changed files with 80 additions and 18 deletions

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}
}
}

View File

@ -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()

View File

@ -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.

View File

@ -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);