Skip to content

allow customizing httpRequestRetryHandler #362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/main/java/com/arangodb/ArangoDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.arangodb.velocypack.*;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.Response;
import org.apache.http.client.HttpRequestRetryHandler;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -187,6 +188,23 @@ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
return this;
}

/**
* Sets the {@link HttpRequestRetryHandler} to be used when using http protocol.
*
* @param httpRequestRetryHandler HttpRequestRetryHandler to be used
* @return {@link ArangoDB.Builder}
*
* <br /><br />
* NOTE:
* Some ArangoDB HTTP endpoints do not honor RFC-2616 HTTP 1.1 specification in respect to
* <a href="https://tools.ietf.org/html/rfc2616#section-9.1">9.1 Safe and Idempotent Methods</a>.
* Please refer to <a href="https://www.arangodb.com/docs/stable/http/">HTTP API Documentation</a> for details.
*/
public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
setHttpRequestRetryHandler(httpRequestRetryHandler);
return this;
}

/**
* Sets the chunk size when {@link Protocol#VST} is used.
*
Expand Down Expand Up @@ -584,7 +602,7 @@ public synchronized ArangoDB build() {
final ConnectionFactory connectionFactory = (protocol == null || Protocol.VST == protocol)
? new VstConnectionFactorySync(host, timeout, connectionTtl, useSsl, sslContext)
: new HttpConnectionFactory(timeout, user, password, useSsl, sslContext, hostnameVerifier, custom,
protocol, connectionTtl, httpCookieSpec);
protocol, connectionTtl, httpCookieSpec, httpRequestRetryHandler);

final Collection<Host> hostList = createHostList(max, connectionFactory);
final HostResolver hostResolver = createHostResolver(hostList, max, connectionFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.arangodb.util.ArangoSerializer;
import com.arangodb.velocypack.VPack;
import com.arangodb.velocypack.VPackParser;
import org.apache.http.client.HttpRequestRetryHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -74,6 +75,7 @@ public abstract class InternalArangoDBBuilder {
protected String password;
protected Boolean useSsl;
protected String httpCookieSpec;
protected HttpRequestRetryHandler httpRequestRetryHandler;
protected SSLContext sslContext;
protected HostnameVerifier hostnameVerifier;
protected Integer chunksize;
Expand Down Expand Up @@ -166,6 +168,10 @@ protected void setHostnameVerifier(final HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
}

protected void setHttpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
this.httpRequestRetryHandler = httpRequestRetryHandler;
}

protected void setChunksize(final Integer chunksize) {
this.chunksize = chunksize;
}
Expand Down
14 changes: 11 additions & 3 deletions src/main/java/com/arangodb/internal/http/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
Expand Down Expand Up @@ -90,6 +91,7 @@ public static class Builder {
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private Integer timeout;
private HttpRequestRetryHandler httpRequestRetryHandler;

public Builder user(final String user) {
this.user = user;
Expand Down Expand Up @@ -146,8 +148,14 @@ public Builder timeout(final Integer timeout) {
return this;
}

public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
this.httpRequestRetryHandler = httpRequestRetryHandler;
return this;
}

public HttpConnection build() {
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util, contentType, ttl, httpCookieSpec);
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util,
contentType, ttl, httpCookieSpec, httpRequestRetryHandler);
}
}

Expand All @@ -162,7 +170,7 @@ public HttpConnection build() {

private HttpConnection(final HostDescription host, final Integer timeout, final String user, final String password,
final Boolean useSsl, final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol contentType,
final Long ttl, final String httpCookieSpec) {
final Long ttl, final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
super();
this.host = host;
this.user = user;
Expand Down Expand Up @@ -197,7 +205,7 @@ private HttpConnection(final HostDescription host, final Integer timeout, final
final ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> HttpConnection.this.getKeepAliveDuration(response);
final HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig.build())
.setConnectionManager(cm).setKeepAliveStrategy(keepAliveStrategy)
.setRetryHandler(new DefaultHttpRequestRetryHandler());
.setRetryHandler(httpRequestRetryHandler != null ? httpRequestRetryHandler : new DefaultHttpRequestRetryHandler());
if (ttl != null) {
builder.setConnectionTimeToLive(ttl, TimeUnit.MILLISECONDS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.arangodb.internal.net.ConnectionFactory;
import com.arangodb.internal.net.HostDescription;
import com.arangodb.util.ArangoSerialization;
import org.apache.http.client.HttpRequestRetryHandler;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand All @@ -37,12 +38,13 @@ public class HttpConnectionFactory implements ConnectionFactory {
private final HttpConnection.Builder builder;

public HttpConnectionFactory(final Integer timeout, final String user, final String password, final Boolean useSsl,
final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol protocol,
final Long connectionTtl, String httpCookieSpec) {
final SSLContext sslContext, final HostnameVerifier hostnameVerifier,
final ArangoSerialization util, final Protocol protocol, final Long connectionTtl,
final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
super();
builder = new HttpConnection.Builder().timeout(timeout).user(user).password(password).useSsl(useSsl)
.sslContext(sslContext).hostnameVerifier(hostnameVerifier).serializationUtil(util).contentType(protocol)
.ttl(connectionTtl).httpCookieSpec(httpCookieSpec);
.ttl(connectionTtl).httpCookieSpec(httpCookieSpec).httpRequestRetryHandler(httpRequestRetryHandler);

}

Expand Down
77 changes: 77 additions & 0 deletions src/test/java/com/arangodb/internal/http/HttpRetryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* DISCLAIMER
*
* Copyright 2016 ArangoDB GmbH, Cologne, Germany
*
* Licensed 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.
*
* Copyright holder is ArangoDB GmbH, Cologne, Germany
*/

package com.arangodb.internal.http;


import com.arangodb.ArangoDB;
import com.arangodb.ArangoDBException;
import com.arangodb.Protocol;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.protocol.HttpContext;
import org.junit.Ignore;
import org.junit.Test;

import java.io.IOException;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.fail;

/**
* @author Michele Rastelli
*/
public class HttpRetryTest {

private final static int RETRIES = 2;

private static class TestRetryHandler implements HttpRequestRetryHandler {
private int retriesCounter = 0;

@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
return ++retriesCounter < RETRIES;
}

}

/**
* remove host from src/test/resources/arangodb.properties to run this test
*/
@Test
@Ignore
public void retry() {
TestRetryHandler retryHandler = new TestRetryHandler();
ArangoDB arangoDB = new ArangoDB.Builder()
.host("wrongHost", 8529)
.useProtocol(Protocol.HTTP_JSON)
.httpRequestRetryHandler(retryHandler)
.build();

try {
arangoDB.getVersion();
fail("it should throw I/O exception");
} catch (ArangoDBException e) {
assertThat(retryHandler.retriesCounter, is(RETRIES));
}

}

}