Skip to content

Commit 2ece387

Browse files
committed
GH-5124 introduce number of connections and also reduce timeouts (+1 squashed commit)
Squashed commits: [9aa87b594c] GH-5124 introduce number of connections and also reduce timeouts
1 parent 20416e2 commit 2ece387

1 file changed

Lines changed: 138 additions & 46 deletions

File tree

core/http/client/src/main/java/org/eclipse/rdf4j/http/client/SharedHttpClientSessionManager.java

Lines changed: 138 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import org.apache.http.client.utils.HttpClientUtils;
3535
import org.apache.http.impl.client.CloseableHttpClient;
3636
import org.apache.http.impl.client.HttpClientBuilder;
37-
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
3837
import org.apache.http.protocol.HttpContext;
3938
import org.eclipse.rdf4j.http.client.util.HttpClientBuilders;
4039
import org.slf4j.Logger;
@@ -46,35 +45,56 @@
4645
* @author James Leigh
4746
*/
4847
public class SharedHttpClientSessionManager implements HttpClientSessionManager, HttpClientDependent {
48+
49+
private static final AtomicLong threadCount = new AtomicLong();
50+
4951
/**
5052
* Configurable system property {@code org.eclipse.rdf4j.client.executors.corePoolSize} for specifying the
5153
* background executor core thread pool size.
5254
*/
5355
public static final String CORE_POOL_SIZE_PROPERTY = "org.eclipse.rdf4j.client.executors.corePoolSize";
5456

55-
private static final AtomicLong threadCount = new AtomicLong();
57+
/**
58+
* Configurable system property {@code org.eclipse.rdf4j.client.http.maxConnPerRoute} for specifying the maximum
59+
* number of connections per route (per host). Default is 25.
60+
*
61+
* <p>
62+
* This property determines the maximum number of concurrent connections to a single host (route). Adjusting this
63+
* value can improve performance when communicating with a server that supports multiple concurrent connections.
64+
* </p>
65+
*/
66+
public static final String MAX_CONN_PER_ROUTE_PROPERTY = "org.eclipse.rdf4j.client.http.maxConnPerRoute";
5667

57-
// System property constants for regular timeouts
68+
/**
69+
* Configurable system property {@code org.eclipse.rdf4j.client.http.maxConnTotal} for specifying the maximum total
70+
* number of connections. Default is 50.
71+
*
72+
* <p>
73+
* This property sets the maximum total number of concurrent connections that can be open at the same time.
74+
* Increasing this value allows more simultaneous connections to different hosts, which can improve throughput in
75+
* multi-threaded environments.
76+
* </p>
77+
*/
78+
public static final String MAX_CONN_TOTAL_PROPERTY = "org.eclipse.rdf4j.client.http.maxConnTotal";
5879

5980
/**
6081
* Configurable system property {@code org.eclipse.rdf4j.client.http.connectionTimeout} for specifying the HTTP
61-
* connection timeout in milliseconds for general use. Default is 1 hour.
82+
* connection timeout in milliseconds for general use. Default is 30 seconds.
6283
*
6384
* <p>
6485
* The connection timeout determines the maximum time the client will wait to establish a TCP connection to the
65-
* server. A default of 1 hour is set to allow for potential network delays without causing unnecessary timeouts.
86+
* server. A default of 30 seconds is set to allow for potential network delays without causing unnecessary
87+
* timeouts.
6688
* </p>
6789
*/
6890
public static final String CONNECTION_TIMEOUT_PROPERTY = "org.eclipse.rdf4j.client.http.connectionTimeout";
6991

7092
/**
7193
* Configurable system property {@code org.eclipse.rdf4j.client.http.connectionRequestTimeout} for specifying the
72-
* HTTP connection request timeout in milliseconds for general use. Default is 10 days.
94+
* HTTP connection request timeout in milliseconds for general use. Default is 1 hour.
7395
*
7496
* <p>
75-
* The connection request timeout defines how long the client will wait for a connection from the connection pool. A
76-
* longer timeout is acceptable here since operations like large file uploads may need to wait for an available
77-
* connection.
97+
* The connection request timeout defines how long the client will wait for a connection from the connection pool.
7898
* </p>
7999
*/
80100
public static final String CONNECTION_REQUEST_TIMEOUT_PROPERTY = "org.eclipse.rdf4j.client.http.connectionRequestTimeout";
@@ -94,7 +114,7 @@ public class SharedHttpClientSessionManager implements HttpClientSessionManager,
94114

95115
/**
96116
* Configurable system property {@code org.eclipse.rdf4j.client.sparql.http.connectionTimeout} for specifying the
97-
* HTTP connection timeout in milliseconds when used in SPARQL SERVICE calls. Default is 10 minutes.
117+
* HTTP connection timeout in milliseconds when used in SPARQL SERVICE calls. Default is 5 seconds.
98118
*
99119
* <p>
100120
* A shorter connection timeout is set for SPARQL SERVICE calls to quickly detect unresponsive endpoints in
@@ -105,7 +125,7 @@ public class SharedHttpClientSessionManager implements HttpClientSessionManager,
105125

106126
/**
107127
* Configurable system property {@code org.eclipse.rdf4j.client.sparql.http.connectionRequestTimeout} for specifying
108-
* the HTTP connection request timeout in milliseconds when used in SPARQL SERVICE calls. Default is 6 hours.
128+
* the HTTP connection request timeout in milliseconds when used in SPARQL SERVICE calls. Default is 10 minutes.
109129
*
110130
* <p>
111131
* This timeout controls how long the client waits for a connection from the pool when making SPARQL SERVICE calls.
@@ -117,7 +137,7 @@ public class SharedHttpClientSessionManager implements HttpClientSessionManager,
117137

118138
/**
119139
* Configurable system property {@code org.eclipse.rdf4j.client.sparql.http.socketTimeout} for specifying the HTTP
120-
* socket timeout in milliseconds when used in SPARQL SERVICE calls. Default is 6 hours.
140+
* socket timeout in milliseconds when used in SPARQL SERVICE calls. Default is 1 hour.
121141
*
122142
* <p>
123143
* The socket timeout for SPARQL SERVICE calls is set to a shorter duration to detect unresponsive servers during
@@ -126,84 +146,155 @@ public class SharedHttpClientSessionManager implements HttpClientSessionManager,
126146
*/
127147
public static final String SPARQL_SOCKET_TIMEOUT_PROPERTY = "org.eclipse.rdf4j.client.sparql.http.socketTimeout";
128148

129-
// Default timeout values for general use
149+
// Defaults
150+
151+
/**
152+
* Default core pool size for the executor service. Set to 5.
153+
*
154+
* <p>
155+
* This value determines the number of threads to keep in the pool, even if they are idle. Adjusting this value can
156+
* help manage resource utilization in high-load scenarios.
157+
* </p>
158+
*/
159+
public static final int DEFAULT_CORE_POOL_SIZE = 5;
160+
161+
/**
162+
* Default maximum number of connections per route (per host). Set to 25.
163+
*
164+
* <p>
165+
* This value limits the number of concurrent connections to a single host. Increasing it can improve performance
166+
* when communicating with a server that can handle multiple connections.
167+
* </p>
168+
*/
169+
public static final int DEFAULT_MAX_CONN_PER_ROUTE = 25;
170+
171+
/**
172+
* Default maximum total number of connections. Set to 50.
173+
*
174+
* <p>
175+
* This value limits the total number of concurrent connections that can be open at the same time. Increasing it
176+
* allows for more simultaneous connections to different hosts.
177+
* </p>
178+
*/
179+
public static final int DEFAULT_MAX_CONN_TOTAL = 50;
130180

131181
/**
132-
* Default HTTP connection timeout in milliseconds for general use. Set to 1 hour.
182+
* Default HTTP connection timeout in milliseconds for general use. Set to 30 seconds.
183+
*
184+
* <p>
185+
* The connection timeout determines the maximum time the client will wait to establish a TCP connection to the
186+
* server.
187+
* </p>
133188
*/
134-
public static final int DEFAULT_CONNECTION_TIMEOUT = 60 * 60 * 1000; // 1 hour
189+
public static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000; // 30 seconds
135190

136191
/**
137-
* Default HTTP connection request timeout in milliseconds for general use. Set to 10 days.
192+
* Default HTTP connection request timeout in milliseconds for general use. Set to 1 hour.
193+
*
194+
* <p>
195+
* The connection request timeout defines how long the client will wait for a connection from the connection pool.
196+
* </p>
138197
*/
139-
public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 10 * 24 * 60 * 60 * 1000; // 10 days
198+
public static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 60 * 60 * 1000; // 1 hour
140199

141200
/**
142201
* Default HTTP socket timeout in milliseconds for general use. Set to 10 days.
202+
*
203+
* <p>
204+
* The socket timeout controls the maximum period of inactivity between data packets during data transfer. A longer
205+
* timeout is appropriate for large data transfers.
206+
* </p>
143207
*/
144208
public static final int DEFAULT_SOCKET_TIMEOUT = 10 * 24 * 60 * 60 * 1000; // 10 days
145209

146210
// Default timeout values for SPARQL SERVICE calls
147211

148212
/**
149-
* Default HTTP connection timeout in milliseconds for SPARQL SERVICE calls. Set to 10 minutes.
213+
* Default HTTP connection timeout in milliseconds for SPARQL SERVICE calls. Set to 5 seconds.
214+
*
215+
* <p>
216+
* A shorter connection timeout is set for SPARQL SERVICE calls to quickly detect unresponsive endpoints in
217+
* federated queries.
218+
* </p>
219+
*/
220+
public static final int DEFAULT_SPARQL_CONNECTION_TIMEOUT = 5 * 1000; // 5 seconds
221+
222+
/**
223+
* Default HTTP connection request timeout in milliseconds for SPARQL SERVICE calls. Set to 10 minutes.
224+
*
225+
* <p>
226+
* This timeout controls how long the client waits for a connection from the pool when making SPARQL SERVICE calls.
227+
* </p>
228+
*/
229+
public static final int DEFAULT_SPARQL_CONNECTION_REQUEST_TIMEOUT = 10 * 60 * 1000; // 10 minutes
230+
231+
/**
232+
* Default HTTP socket timeout in milliseconds for SPARQL SERVICE calls. Set to 1 hour.
233+
*
234+
* <p>
235+
* The socket timeout for SPARQL SERVICE calls is set to a shorter duration to detect unresponsive servers during
236+
* data transfer.
237+
* </p>
150238
*/
151-
public static final int DEFAULT_SPARQL_CONNECTION_TIMEOUT = 10 * 60 * 1000; // 10 minutes
239+
public static final int DEFAULT_SPARQL_SOCKET_TIMEOUT = 60 * 60 * 1000; // 1 hour
240+
241+
// Values as read from system properties or defaults
152242

153243
/**
154-
* Default HTTP connection request timeout in milliseconds for SPARQL SERVICE calls. Set to 6 hours.
244+
* Core pool size for the executor service, as read from system properties or defaults.
155245
*/
156-
public static final int DEFAULT_SPARQL_CONNECTION_REQUEST_TIMEOUT = 6 * 60 * 60 * 1000; // 6 hours
246+
public static final int CORE_POOL_SIZE = Integer
247+
.parseInt(System.getProperty(CORE_POOL_SIZE_PROPERTY, String.valueOf(DEFAULT_CORE_POOL_SIZE)));
157248

158249
/**
159-
* Default HTTP socket timeout in milliseconds for SPARQL SERVICE calls. Set to 6 hours.
250+
* Maximum number of connections per route (per host), as read from system properties or defaults.
160251
*/
161-
public static final int DEFAULT_SPARQL_SOCKET_TIMEOUT = 6 * 60 * 60 * 1000; // 6 hours
252+
public static final int MAX_CONN_PER_ROUTE = Integer
253+
.parseInt(System.getProperty(MAX_CONN_PER_ROUTE_PROPERTY, String.valueOf(DEFAULT_MAX_CONN_PER_ROUTE)));
162254

163-
// Timeout values as read from system properties or defaults
255+
/**
256+
* Maximum total number of connections, as read from system properties or defaults.
257+
*/
258+
public static final int MAX_CONN_TOTAL = Integer
259+
.parseInt(System.getProperty(MAX_CONN_TOTAL_PROPERTY, String.valueOf(DEFAULT_MAX_CONN_TOTAL)));
164260

165261
/**
166262
* HTTP connection timeout in milliseconds for general use.
167263
*/
168264
public static final int CONNECTION_TIMEOUT = Integer.parseInt(
169-
System.getProperty(CONNECTION_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_CONNECTION_TIMEOUT))
170-
);
265+
System.getProperty(CONNECTION_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_CONNECTION_TIMEOUT)));
171266

172267
/**
173268
* HTTP connection request timeout in milliseconds for general use.
174269
*/
175270
public static final int CONNECTION_REQUEST_TIMEOUT = Integer.parseInt(
176-
System.getProperty(CONNECTION_REQUEST_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_CONNECTION_REQUEST_TIMEOUT))
177-
);
271+
System.getProperty(CONNECTION_REQUEST_TIMEOUT_PROPERTY,
272+
String.valueOf(DEFAULT_CONNECTION_REQUEST_TIMEOUT)));
178273

179274
/**
180275
* HTTP socket timeout in milliseconds for general use.
181276
*/
182-
public static final int SOCKET_TIMEOUT = Integer.parseInt(
183-
System.getProperty(SOCKET_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SOCKET_TIMEOUT))
184-
);
277+
public static final int SOCKET_TIMEOUT = Integer
278+
.parseInt(System.getProperty(SOCKET_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SOCKET_TIMEOUT)));
185279

186280
/**
187281
* HTTP connection timeout in milliseconds for SPARQL SERVICE calls.
188282
*/
189283
public static final int SPARQL_CONNECTION_TIMEOUT = Integer.parseInt(
190-
System.getProperty(SPARQL_CONNECTION_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SPARQL_CONNECTION_TIMEOUT))
191-
);
284+
System.getProperty(SPARQL_CONNECTION_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SPARQL_CONNECTION_TIMEOUT)));
192285

193286
/**
194287
* HTTP connection request timeout in milliseconds for SPARQL SERVICE calls.
195288
*/
196289
public static final int SPARQL_CONNECTION_REQUEST_TIMEOUT = Integer.parseInt(
197290
System.getProperty(SPARQL_CONNECTION_REQUEST_TIMEOUT_PROPERTY,
198-
String.valueOf(DEFAULT_SPARQL_CONNECTION_REQUEST_TIMEOUT))
199-
);
291+
String.valueOf(DEFAULT_SPARQL_CONNECTION_REQUEST_TIMEOUT)));
200292

201293
/**
202294
* HTTP socket timeout in milliseconds for SPARQL SERVICE calls.
203295
*/
204296
public static final int SPARQL_SOCKET_TIMEOUT = Integer.parseInt(
205-
System.getProperty(SPARQL_SOCKET_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SPARQL_SOCKET_TIMEOUT))
206-
);
297+
System.getProperty(SPARQL_SOCKET_TIMEOUT_PROPERTY, String.valueOf(DEFAULT_SPARQL_SOCKET_TIMEOUT)));
207298

208299
// Variables for the currently used timeouts
209300

@@ -214,12 +305,12 @@ public class SharedHttpClientSessionManager implements HttpClientSessionManager,
214305
private final Logger logger = LoggerFactory.getLogger(SharedHttpClientSessionManager.class);
215306

216307
/**
217-
* independent life cycle
308+
* Independent life cycle
218309
*/
219310
private volatile HttpClient httpClient;
220311

221312
/**
222-
* dependent life cycle
313+
* Dependent life cycle
223314
*/
224315
private volatile CloseableHttpClient dependentClient;
225316

@@ -275,7 +366,7 @@ private static class ServiceUnavailableRetryHandler implements ServiceUnavailabl
275366

276367
@Override
277368
public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {
278-
// only retry on `408`
369+
// only retry on HTTP 408 (Request Timeout)
279370
if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_CLIENT_TIMEOUT) {
280371
return false;
281372
}
@@ -287,11 +378,10 @@ public boolean retryRequest(HttpResponse response, int executionCount, HttpConte
287378
return false;
288379
}
289380

290-
// worst case, the connection pool is filled to the max and all of them idled out on the server already
291-
// we then need to clean up the pool and finally retry with a fresh connection. Hence, we need at most
292-
// pooledConnections+1 retries.
293-
// the pool size setting used here is taken from `HttpClientBuilder` when `useSystemProperties()` is used
294-
int pooledConnections = Integer.parseInt(System.getProperty("http.maxConnections", "5"));
381+
// Worst case, the connection pool is filled to the max and all of them idled out on the server already
382+
// We then need to clean up the pool and retry with a fresh connection. Hence, we need at most
383+
// pooledConnections + 1 retries.
384+
int pooledConnections = MAX_CONN_PER_ROUTE;
295385
if (executionCount > (pooledConnections + 1)) {
296386
return false;
297387
}
@@ -332,7 +422,7 @@ public SharedHttpClientSessionManager() {
332422
return thread;
333423
});
334424

335-
Integer corePoolSize = Integer.getInteger(CORE_POOL_SIZE_PROPERTY, 1);
425+
Integer corePoolSize = CORE_POOL_SIZE;
336426
((ThreadPoolExecutor) threadPoolExecutor).setCorePoolSize(corePoolSize);
337427
this.executor = threadPoolExecutor;
338428
}
@@ -486,6 +576,8 @@ private CloseableHttpClient createHttpClient() {
486576
.evictIdleConnections(30, TimeUnit.MINUTES)
487577
.setRetryHandler(retryHandlerStale)
488578
.setServiceUnavailableRetryStrategy(serviceUnavailableRetryHandler)
579+
.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
580+
.setMaxConnTotal(MAX_CONN_TOTAL)
489581
.useSystemProperties()
490582
.setDefaultRequestConfig(requestConfig)
491583
.build();

0 commit comments

Comments
 (0)