Updated Branches:
  refs/heads/master 53134dfa4 -> 8c495ddee

JCLOUDS-137: Retry on HTTP 500 AtmosError 1040


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/8c495dde
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/8c495dde
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/8c495dde

Branch: refs/heads/master
Commit: 8c495ddee4e6ca7e2d2f4ab0fd50210f727648ba
Parents: 53134df
Author: Andrew Gaul <[email protected]>
Authored: Mon Jan 6 14:52:40 2014 -0800
Committer: Andrew Gaul <[email protected]>
Committed: Tue Feb 11 12:12:54 2014 -0800

----------------------------------------------------------------------
 .../atmos/config/AtmosRestClientModule.java     |  2 +
 .../handlers/AtmosServerErrorRetryHandler.java  | 85 +++++++++++++++++++
 .../AtmosServerErrorRetryHandlerTest.java       | 86 ++++++++++++++++++++
 3 files changed, 173 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/8c495dde/apis/atmos/src/main/java/org/jclouds/atmos/config/AtmosRestClientModule.java
----------------------------------------------------------------------
diff --git 
a/apis/atmos/src/main/java/org/jclouds/atmos/config/AtmosRestClientModule.java 
b/apis/atmos/src/main/java/org/jclouds/atmos/config/AtmosRestClientModule.java
index b35f6b1..4832875 100644
--- 
a/apis/atmos/src/main/java/org/jclouds/atmos/config/AtmosRestClientModule.java
+++ 
b/apis/atmos/src/main/java/org/jclouds/atmos/config/AtmosRestClientModule.java
@@ -25,6 +25,7 @@ import org.jclouds.Constants;
 import org.jclouds.atmos.AtmosAsyncClient;
 import org.jclouds.atmos.AtmosClient;
 import org.jclouds.atmos.handlers.AtmosClientErrorRetryHandler;
+import org.jclouds.atmos.handlers.AtmosServerErrorRetryHandler;
 import org.jclouds.atmos.handlers.ParseAtmosErrorFromXmlContent;
 import org.jclouds.date.DateService;
 import org.jclouds.date.TimeStamp;
@@ -92,6 +93,7 @@ public class AtmosRestClientModule extends 
RestClientModule<AtmosClient, AtmosAs
    @Override
    protected void bindRetryHandlers() {
       
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(AtmosClientErrorRetryHandler.class);
+      
bind(HttpRetryHandler.class).annotatedWith(ServerError.class).to(AtmosServerErrorRetryHandler.class);
    }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds/blob/8c495dde/apis/atmos/src/main/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandler.java
----------------------------------------------------------------------
diff --git 
a/apis/atmos/src/main/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandler.java
 
b/apis/atmos/src/main/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandler.java
new file mode 100644
index 0000000..3a4a81e
--- /dev/null
+++ 
b/apis/atmos/src/main/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandler.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.atmos.handlers;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import org.jclouds.Constants;
+import org.jclouds.atmos.domain.AtmosError;
+import org.jclouds.atmos.util.AtmosUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.logging.Logger;
+
+import com.google.inject.Inject;
+
+/**
+ * Handles Retryable responses with error codes in the 5xx range
+ *
+ * @see Error codes section at <a 
href="https://www.synaptic.att.com/assets/us/en/home/Atmos_Programmers_Guide_1.3.4A.pdf";
 />
+ * @author Andrew Gaul
+ */
+public class AtmosServerErrorRetryHandler implements HttpRetryHandler {
+   private final AtmosUtils utils;
+   private final BackoffLimitedRetryHandler backoffHandler;
+
+   @Inject
+   public AtmosServerErrorRetryHandler(BackoffLimitedRetryHandler 
backoffHandler,
+            AtmosUtils utils) {
+      this.backoffHandler = backoffHandler;
+      this.utils = utils;
+   }
+
+   @Inject(optional = true)
+   @Named(Constants.PROPERTY_MAX_RETRIES)
+   private int retryCountLimit = 5;
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   public boolean shouldRetryRequest(HttpCommand command, HttpResponse 
response) {
+      if (command.getFailureCount() > retryCountLimit) {
+         return false;
+      }
+      if (response.getStatusCode() == 500) {
+         byte[] content = HttpUtils.closeClientButKeepContentStream(response);
+         // Content can be null in the case of HEAD requests
+         if (content != null) {
+            try {
+               AtmosError error = utils.parseAtmosErrorFromContent(command, 
response,
+                        new String(content));
+               if (error.getCode() == 1040) {  // The server is busy. Please 
try again.
+                  return backoffHandler.shouldRetryRequest(command, response);
+               }
+               // don't increment count before here, since backoff handler 
does already
+               command.incrementFailureCount();
+            } catch (HttpException e) {
+               logger.warn(e, "error parsing response: %s", new 
String(content));
+            }
+         } else {
+            command.incrementFailureCount();
+         }
+         return false;
+      }
+      return false;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/8c495dde/apis/atmos/src/test/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/apis/atmos/src/test/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandlerTest.java
 
b/apis/atmos/src/test/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandlerTest.java
new file mode 100644
index 0000000..8cd8b15
--- /dev/null
+++ 
b/apis/atmos/src/test/java/org/jclouds/atmos/handlers/AtmosServerErrorRetryHandlerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.atmos.binders;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.atmos.domain.AtmosError;
+import org.jclouds.atmos.handlers.AtmosServerErrorRetryHandler;
+import org.jclouds.atmos.util.AtmosUtils;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+/**
+ * Tests behavior of {@code AtmosServerErrorRetryHandler}
+ *
+ * @author Andrew Gaul
+ */
+@Test(groups = "unit")
+public class AtmosServerErrorRetryHandlerTest {
+   private static final String HTTP_MESSAGE_FORMAT =
+         "<?xml version='1.0' encoding='UTF-8'?>\n" +
+         "<Error>\n" +
+         "<Code>%d</Code>\n" +
+         "<Message>%s</Message>\n" +
+         "</Error>\n";
+
+   @Test
+   public void testGet500WithoutError() {
+      AtmosUtils utils = createMock(AtmosUtils.class);
+      BackoffLimitedRetryHandler backoffLimitedRetryHandler = 
createMock(BackoffLimitedRetryHandler.class);
+      HttpCommand command = createMock(HttpCommand.class);
+
+      expect(command.getFailureCount()).andReturn(0).once();
+      expect(command.incrementFailureCount()).andReturn(1).once();
+
+      replay(utils, backoffLimitedRetryHandler, command);
+
+      AtmosServerErrorRetryHandler retry = new 
AtmosServerErrorRetryHandler(backoffLimitedRetryHandler, utils);
+
+      assertFalse(retry.shouldRetryRequest(command, 
HttpResponse.builder().statusCode(500).build()));
+
+      verify(utils, backoffLimitedRetryHandler, command);
+   }
+
+   @Test
+   public void testGet500WithError1040() {
+      AtmosUtils utils = createMock(AtmosUtils.class);
+      BackoffLimitedRetryHandler backoffLimitedRetryHandler = 
createMock(BackoffLimitedRetryHandler.class);
+      HttpCommand command = createMock(HttpCommand.class);
+      String content = String.format(HTTP_MESSAGE_FORMAT, 1040, "The server is 
busy. Please try again");
+      HttpResponse response = 
HttpResponse.builder().statusCode(500).payload(content).build();
+
+      expect(command.getFailureCount()).andReturn(0).once();
+      expect(utils.parseAtmosErrorFromContent(command, response, 
content)).andReturn(new AtmosError(1040, "The server is busy. Please try 
again")).once();
+      expect(backoffLimitedRetryHandler.shouldRetryRequest(command, 
response)).andReturn(true).once();
+
+      replay(utils, backoffLimitedRetryHandler, command);
+
+      AtmosServerErrorRetryHandler retry = new 
AtmosServerErrorRetryHandler(backoffLimitedRetryHandler, utils);
+
+      assertTrue(retry.shouldRetryRequest(command, response));
+
+      verify(utils, backoffLimitedRetryHandler, command);
+   }
+}

Reply via email to