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

View File

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

View File

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

View File

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

View File

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

View File

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