Skip to content

Commit 37b8917

Browse files
authored
allow customizing httpRequestRetryHandler (#362)
* allow customizing httpRequestRetryHandler * HttpRetryTest
1 parent d0fcc9c commit 37b8917

File tree

5 files changed

+118
-7
lines changed

5 files changed

+118
-7
lines changed

src/main/java/com/arangodb/ArangoDB.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.arangodb.velocypack.*;
4646
import com.arangodb.velocystream.Request;
4747
import com.arangodb.velocystream.Response;
48+
import org.apache.http.client.HttpRequestRetryHandler;
4849

4950
import javax.net.ssl.HostnameVerifier;
5051
import javax.net.ssl.SSLContext;
@@ -187,6 +188,23 @@ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
187188
return this;
188189
}
189190

191+
/**
192+
* Sets the {@link HttpRequestRetryHandler} to be used when using http protocol.
193+
*
194+
* @param httpRequestRetryHandler HttpRequestRetryHandler to be used
195+
* @return {@link ArangoDB.Builder}
196+
*
197+
* <br /><br />
198+
* NOTE:
199+
* Some ArangoDB HTTP endpoints do not honor RFC-2616 HTTP 1.1 specification in respect to
200+
* <a href="https://tools.ietf.org/html/rfc2616#section-9.1">9.1 Safe and Idempotent Methods</a>.
201+
* Please refer to <a href="https://www.arangodb.com/docs/stable/http/">HTTP API Documentation</a> for details.
202+
*/
203+
public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
204+
setHttpRequestRetryHandler(httpRequestRetryHandler);
205+
return this;
206+
}
207+
190208
/**
191209
* Sets the chunk size when {@link Protocol#VST} is used.
192210
*
@@ -584,7 +602,7 @@ public synchronized ArangoDB build() {
584602
final ConnectionFactory connectionFactory = (protocol == null || Protocol.VST == protocol)
585603
? new VstConnectionFactorySync(host, timeout, connectionTtl, useSsl, sslContext)
586604
: new HttpConnectionFactory(timeout, user, password, useSsl, sslContext, hostnameVerifier, custom,
587-
protocol, connectionTtl, httpCookieSpec);
605+
protocol, connectionTtl, httpCookieSpec, httpRequestRetryHandler);
588606

589607
final Collection<Host> hostList = createHostList(max, connectionFactory);
590608
final HostResolver hostResolver = createHostResolver(hostList, max, connectionFactory);

src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.arangodb.util.ArangoSerializer;
3232
import com.arangodb.velocypack.VPack;
3333
import com.arangodb.velocypack.VPackParser;
34+
import org.apache.http.client.HttpRequestRetryHandler;
3435
import org.slf4j.Logger;
3536
import org.slf4j.LoggerFactory;
3637

@@ -74,6 +75,7 @@ public abstract class InternalArangoDBBuilder {
7475
protected String password;
7576
protected Boolean useSsl;
7677
protected String httpCookieSpec;
78+
protected HttpRequestRetryHandler httpRequestRetryHandler;
7779
protected SSLContext sslContext;
7880
protected HostnameVerifier hostnameVerifier;
7981
protected Integer chunksize;
@@ -166,6 +168,10 @@ protected void setHostnameVerifier(final HostnameVerifier hostnameVerifier) {
166168
this.hostnameVerifier = hostnameVerifier;
167169
}
168170

171+
protected void setHttpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
172+
this.httpRequestRetryHandler = httpRequestRetryHandler;
173+
}
174+
169175
protected void setChunksize(final Integer chunksize) {
170176
this.chunksize = chunksize;
171177
}

src/main/java/com/arangodb/internal/http/HttpConnection.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.http.auth.AuthenticationException;
3636
import org.apache.http.auth.Credentials;
3737
import org.apache.http.auth.UsernamePasswordCredentials;
38+
import org.apache.http.client.HttpRequestRetryHandler;
3839
import org.apache.http.client.config.RequestConfig;
3940
import org.apache.http.client.methods.*;
4041
import org.apache.http.client.utils.URLEncodedUtils;
@@ -90,6 +91,7 @@ public static class Builder {
9091
private SSLContext sslContext;
9192
private HostnameVerifier hostnameVerifier;
9293
private Integer timeout;
94+
private HttpRequestRetryHandler httpRequestRetryHandler;
9395

9496
public Builder user(final String user) {
9597
this.user = user;
@@ -146,8 +148,14 @@ public Builder timeout(final Integer timeout) {
146148
return this;
147149
}
148150

151+
public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
152+
this.httpRequestRetryHandler = httpRequestRetryHandler;
153+
return this;
154+
}
155+
149156
public HttpConnection build() {
150-
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util, contentType, ttl, httpCookieSpec);
157+
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util,
158+
contentType, ttl, httpCookieSpec, httpRequestRetryHandler);
151159
}
152160
}
153161

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

163171
private HttpConnection(final HostDescription host, final Integer timeout, final String user, final String password,
164172
final Boolean useSsl, final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol contentType,
165-
final Long ttl, final String httpCookieSpec) {
173+
final Long ttl, final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
166174
super();
167175
this.host = host;
168176
this.user = user;
@@ -197,7 +205,7 @@ private HttpConnection(final HostDescription host, final Integer timeout, final
197205
final ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> HttpConnection.this.getKeepAliveDuration(response);
198206
final HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig.build())
199207
.setConnectionManager(cm).setKeepAliveStrategy(keepAliveStrategy)
200-
.setRetryHandler(new DefaultHttpRequestRetryHandler());
208+
.setRetryHandler(httpRequestRetryHandler != null ? httpRequestRetryHandler : new DefaultHttpRequestRetryHandler());
201209
if (ttl != null) {
202210
builder.setConnectionTimeToLive(ttl, TimeUnit.MILLISECONDS);
203211
}

src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import com.arangodb.internal.net.ConnectionFactory;
2626
import com.arangodb.internal.net.HostDescription;
2727
import com.arangodb.util.ArangoSerialization;
28+
import org.apache.http.client.HttpRequestRetryHandler;
2829

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

3940
public HttpConnectionFactory(final Integer timeout, final String user, final String password, final Boolean useSsl,
40-
final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol protocol,
41-
final Long connectionTtl, String httpCookieSpec) {
41+
final SSLContext sslContext, final HostnameVerifier hostnameVerifier,
42+
final ArangoSerialization util, final Protocol protocol, final Long connectionTtl,
43+
final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
4244
super();
4345
builder = new HttpConnection.Builder().timeout(timeout).user(user).password(password).useSsl(useSsl)
4446
.sslContext(sslContext).hostnameVerifier(hostnameVerifier).serializationUtil(util).contentType(protocol)
45-
.ttl(connectionTtl).httpCookieSpec(httpCookieSpec);
47+
.ttl(connectionTtl).httpCookieSpec(httpCookieSpec).httpRequestRetryHandler(httpRequestRetryHandler);
4648

4749
}
4850

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* DISCLAIMER
3+
*
4+
* Copyright 2016 ArangoDB GmbH, Cologne, Germany
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
*/
20+
21+
package com.arangodb.internal.http;
22+
23+
24+
import com.arangodb.ArangoDB;
25+
import com.arangodb.ArangoDBException;
26+
import com.arangodb.Protocol;
27+
import org.apache.http.client.HttpRequestRetryHandler;
28+
import org.apache.http.protocol.HttpContext;
29+
import org.junit.Ignore;
30+
import org.junit.Test;
31+
32+
import java.io.IOException;
33+
34+
import static org.hamcrest.MatcherAssert.assertThat;
35+
import static org.hamcrest.Matchers.is;
36+
import static org.junit.Assert.fail;
37+
38+
/**
39+
* @author Michele Rastelli
40+
*/
41+
public class HttpRetryTest {
42+
43+
private final static int RETRIES = 2;
44+
45+
private static class TestRetryHandler implements HttpRequestRetryHandler {
46+
private int retriesCounter = 0;
47+
48+
@Override
49+
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
50+
return ++retriesCounter < RETRIES;
51+
}
52+
53+
}
54+
55+
/**
56+
* remove host from src/test/resources/arangodb.properties to run this test
57+
*/
58+
@Test
59+
@Ignore
60+
public void retry() {
61+
TestRetryHandler retryHandler = new TestRetryHandler();
62+
ArangoDB arangoDB = new ArangoDB.Builder()
63+
.host("wrongHost", 8529)
64+
.useProtocol(Protocol.HTTP_JSON)
65+
.httpRequestRetryHandler(retryHandler)
66+
.build();
67+
68+
try {
69+
arangoDB.getVersion();
70+
fail("it should throw I/O exception");
71+
} catch (ArangoDBException e) {
72+
assertThat(retryHandler.retriesCounter, is(RETRIES));
73+
}
74+
75+
}
76+
77+
}

0 commit comments

Comments
 (0)