title: Async HTTP post retry and exhaust after max retries
body: <p>How can I exhaust retries after a number of failed async request calls?
  I am using <a href="https://github.com/AsyncHttpClient/async-http-client" rel="nofollow noreferrer">AsyncHttpClient</a> to send requests to our server. In case of request timeouts, connection exceptions, etc., I would like the client to retry N times and throw a custom exception. The calling method should receive this exception or it can be left unhandled.</p>
  <pre class="lang-java prettyprint-override"><code>// calls post
  public void call(String data) throws CustomException {
      
      asyncHttpClient.post(data, 10);
  
  }
  </code></pre>
  <pre class="lang-java prettyprint-override"><code>// posts data to http endpoint
  public void post(String data, int retries) throw CustomException {
      // if retries are exhausted, throw CustomException to call()
      if (retry &lt;= 0) {
          throw new CustomException(&quot;exc&quot;);
      }
  
      BoundRequest request = httpClient.preparePost(&quot;http_endpoint&quot;);
      ListenableFuture&lt;Response&gt; responseFuture = httpClient.post(request);
   
      responseFuture.addListener(() -&gt; {
          Response response = null;
          int status = 0;
          try {
  
              response = responseFuture.get();
              status = response.getStatusCode();
  
              // HTTP_ACCEPTED = {200, 201, 202}
              if (ArrayUtils.contains(HTTP_ACCEPTED, status)) {
                  // ok
              } else {
                  sleep(10);
                  post(data, retry - 1);
              }
          } catch (InterruptedException e) {
              sleep(10);
              post(data, retry - 1);
  
          } catch (ExecutionException e) {
              // ConnectionException
              // RequestTimeoutException
              sleep(10); // 10 seconds
              post(data, retry - 1);
          } catch (Exception e) {
              sleep(10); // 10 seconds
              post(data, retry - 1 );
          } finally {
              responseFuture.done();
          }
      },  Runnable::run);
  
  } 
  </code></pre>
  <p>This approach has a few problems:</p>
  <ol>
  <li>uses recursive calls to retry.</li>
  <li>the <code>CustomException</code> seems like it is never thrown and after retries == 0, the control goes back to the <code>finally</code> block.</li>
  </ol>
  <pre><code>...
  } catch (ExecutionException e) {
      // ConnectionException
      // RequestTimeoutException
      sleep(10); // 10 seconds
      try {
          post(data, retry - 1);
      } catch (CustomException e) {
      }
  }
  ...
  </code></pre>