46
46
import software .amazon .awssdk .utils .AttributeMap ;
47
47
import software .amazon .awssdk .utils .IoUtils ;
48
48
import software .amazon .awssdk .utils .Logger ;
49
+ import software .amazon .awssdk .utils .NumericUtils ;
49
50
import software .amazon .awssdk .utils .Validate ;
50
51
51
52
/**
@@ -64,6 +65,14 @@ public final class AwsCrtAsyncHttpClient implements SdkAsyncHttpClient {
64
65
private static final String AWS_COMMON_RUNTIME = "AwsCommonRuntime" ;
65
66
private static final int DEFAULT_STREAM_WINDOW_SIZE = 16 * 1024 * 1024 ; // 16 MB
66
67
68
+ private static final Duration CRT_SDK_DEFAULT_CONNECTION_TIMEOUT = Duration .ofSeconds (3 );
69
+ // Override default connection timeout for Crt client to be in line with the CRT default:
70
+ // https://github.com/awslabs/aws-crt-java/blob/main/src/main/java/software/amazon/awssdk/crt/io/SocketOptions.java#L79
71
+ private static final AttributeMap CRT_HTTP_DEFAULTS =
72
+ AttributeMap .builder ()
73
+ .put (SdkHttpConfigurationOption .CONNECTION_TIMEOUT , CRT_SDK_DEFAULT_CONNECTION_TIMEOUT )
74
+ .build ();
75
+
67
76
private final Map <URI , HttpClientConnectionManager > connectionPools = new ConcurrentHashMap <>();
68
77
private final LinkedList <CrtResource > ownedSubResources = new LinkedList <>();
69
78
private final ClientBootstrap bootstrap ;
@@ -84,7 +93,7 @@ private AwsCrtAsyncHttpClient(DefaultBuilder builder, AttributeMap config) {
84
93
Validate .isPositive (builder .readBufferSize , "readBufferSize" );
85
94
86
95
try (ClientBootstrap clientBootstrap = new ClientBootstrap (null , null );
87
- SocketOptions clientSocketOptions = new SocketOptions ( );
96
+ SocketOptions clientSocketOptions = buildSocketOptions ( builder , config );
88
97
TlsContextOptions clientTlsContextOptions = TlsContextOptions .createDefaultClient () // NOSONAR
89
98
.withCipherPreference (builder .cipherPreference )
90
99
.withVerifyPeer (!config .get (SdkHttpConfigurationOption .TRUST_ALL_CERTIFICATES ));
@@ -138,6 +147,26 @@ private HttpProxyOptions buildProxyOptions(ProxyConfiguration proxyConfiguration
138
147
return clientProxyOptions ;
139
148
}
140
149
150
+ private SocketOptions buildSocketOptions (DefaultBuilder builder , AttributeMap config ) {
151
+ SocketOptions clientSocketOptions = new SocketOptions ();
152
+
153
+ Duration connectionTimeout = config .get (SdkHttpConfigurationOption .CONNECTION_TIMEOUT );
154
+ if (connectionTimeout != null ) {
155
+ clientSocketOptions .connectTimeoutMs = NumericUtils .saturatedCast (connectionTimeout .toMillis ());
156
+ }
157
+
158
+ TcpKeepAliveConfiguration tcpKeepAliveConfiguration = builder .tcpKeepAliveConfiguration ;
159
+ if (tcpKeepAliveConfiguration != null ) {
160
+ clientSocketOptions .keepAliveIntervalSecs =
161
+ NumericUtils .saturatedCast (tcpKeepAliveConfiguration .keepAliveInterval ().getSeconds ());
162
+ clientSocketOptions .keepAliveTimeoutSecs =
163
+ NumericUtils .saturatedCast (tcpKeepAliveConfiguration .keepAliveTimeout ().getSeconds ());
164
+
165
+ }
166
+
167
+ return clientSocketOptions ;
168
+ }
169
+
141
170
/**
142
171
* Marks a Native CrtResource as owned by the current Java Object.
143
172
*
@@ -312,10 +341,10 @@ public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClien
312
341
Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer );
313
342
314
343
/**
315
- * Configure the health checks for for all connections established by this client.
344
+ * Configure the health checks for all connections established by this client.
316
345
*
317
346
* <p>
318
- * eg: you can set a throughput threshold for the a connection to be considered healthy.
347
+ * eg: you can set a throughput threshold for a connection to be considered healthy.
319
348
* If the connection falls below this threshold for a configurable amount of time,
320
349
* then the connection is considered unhealthy and will be shut down.
321
350
*
@@ -325,10 +354,10 @@ public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClien
325
354
Builder connectionHealthChecksConfiguration (ConnectionHealthChecksConfiguration healthChecksConfiguration );
326
355
327
356
/**
328
- * A convenience method to configure the health checks for for all connections established by this client.
357
+ * A convenience method to configure the health checks for all connections established by this client.
329
358
*
330
359
* <p>
331
- * eg: you can set a throughput threshold for the a connection to be considered healthy.
360
+ * eg: you can set a throughput threshold for a connection to be considered healthy.
332
361
* If the connection falls below this threshold for a configurable amount of time,
333
362
* then the connection is considered unhealthy and will be shut down.
334
363
*
@@ -340,9 +369,46 @@ Builder connectionHealthChecksConfiguration(Consumer<ConnectionHealthChecksConfi
340
369
healthChecksConfigurationBuilder );
341
370
342
371
/**
343
- * Configure the maximum amount of time that a connection should be allowed to remain open while idle.
372
+ * The amount of time to wait when initially establishing a connection before giving up and timing out. The maximum
373
+ * possible value, in ms, is the value of {@link Integer#MAX_VALUE}, any longer duration will be reduced to the maximum
374
+ * possible value. If not specified, the connection timeout duration will be set to value defined in
375
+ * {@link AwsCrtAsyncHttpClient#CRT_SDK_DEFAULT_CONNECTION_TIMEOUT}.
344
376
*/
345
377
Builder connectionMaxIdleTime (Duration connectionMaxIdleTime );
378
+
379
+ /**
380
+ * Configure connection socket timeout
381
+ */
382
+ Builder connectionTimeout (Duration connectionTimeout );
383
+
384
+ /**
385
+ * Configure whether to enable TCP Keep-alive and relevant configuration for all connections established by this client.
386
+ *
387
+ * <p>
388
+ * By default, keepAlive is disabled and this is not required.
389
+ * tcpKeepAlive is enabled by providing this configuration and specifying
390
+ * periodic keepalive packet intervals and timeouts
391
+ * This may be required for certain connections for longer durations than default socket timeouts
392
+ *
393
+ * @param tcpKeepAliveConfiguration The TCP keep-alive configuration to use
394
+ * @return The builder of the method chaining.
395
+ */
396
+ Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration );
397
+
398
+ /**
399
+ * Configure whether to enable TCP Keep-alive and relevant configuration for all connections established by this client.
400
+ *
401
+ * <p>
402
+ * By default, keepAlive is disabled and this is not required.
403
+ * tcpKeepAlive is enabled by providing this configuration and specifying
404
+ * periodic keepalive packet intervals and timeouts
405
+ * This may be required for certain connections for longer durations than default socket timeouts
406
+ *
407
+ * @param tcpKeepAliveConfigurationBuilder The TCP keep-alive configuration builder to use
408
+ * @return The builder of the method chaining.
409
+ */
410
+ Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
411
+ tcpKeepAliveConfigurationBuilder );
346
412
}
347
413
348
414
/**
@@ -355,20 +421,23 @@ private static final class DefaultBuilder implements Builder {
355
421
private int readBufferSize = DEFAULT_STREAM_WINDOW_SIZE ;
356
422
private ProxyConfiguration proxyConfiguration ;
357
423
private ConnectionHealthChecksConfiguration connectionHealthChecksConfiguration ;
424
+ private TcpKeepAliveConfiguration tcpKeepAliveConfiguration ;
358
425
359
426
private DefaultBuilder () {
360
427
}
361
428
362
429
@ Override
363
430
public SdkAsyncHttpClient build () {
364
431
return new AwsCrtAsyncHttpClient (this , standardOptions .build ()
432
+ .merge (CRT_HTTP_DEFAULTS )
365
433
.merge (SdkHttpConfigurationOption .GLOBAL_HTTP_DEFAULTS ));
366
434
}
367
435
368
436
@ Override
369
437
public SdkAsyncHttpClient buildWithDefaults (AttributeMap serviceDefaults ) {
370
438
return new AwsCrtAsyncHttpClient (this , standardOptions .build ()
371
439
.merge (serviceDefaults )
440
+ .merge (CRT_HTTP_DEFAULTS )
372
441
.merge (SdkHttpConfigurationOption .GLOBAL_HTTP_DEFAULTS ));
373
442
}
374
443
@@ -417,10 +486,32 @@ public Builder connectionHealthChecksConfiguration(Consumer<ConnectionHealthChec
417
486
418
487
@ Override
419
488
public Builder connectionMaxIdleTime (Duration connectionMaxIdleTime ) {
489
+ Validate .isPositive (connectionMaxIdleTime , "connectionMaxIdleTime" );
420
490
standardOptions .put (SdkHttpConfigurationOption .CONNECTION_MAX_IDLE_TIMEOUT , connectionMaxIdleTime );
421
491
return this ;
422
492
}
423
493
494
+ @ Override
495
+ public Builder connectionTimeout (Duration connectionTimeout ) {
496
+ Validate .isPositive (connectionTimeout , "connectionTimeout" );
497
+ standardOptions .put (SdkHttpConfigurationOption .CONNECTION_TIMEOUT , connectionTimeout );
498
+ return this ;
499
+ }
500
+
501
+ @ Override
502
+ public Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration ) {
503
+ this .tcpKeepAliveConfiguration = tcpKeepAliveConfiguration ;
504
+ return this ;
505
+ }
506
+
507
+ @ Override
508
+ public Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
509
+ tcpKeepAliveConfigurationBuilder ) {
510
+ TcpKeepAliveConfiguration .Builder builder = TcpKeepAliveConfiguration .builder ();
511
+ tcpKeepAliveConfigurationBuilder .accept (builder );
512
+ return tcpKeepAliveConfiguration (builder .build ());
513
+ }
514
+
424
515
@ Override
425
516
public Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer ) {
426
517
ProxyConfiguration .Builder builder = ProxyConfiguration .builder ();
0 commit comments