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
/**
@@ -76,6 +77,14 @@ public final class AwsCrtAsyncHttpClient implements SdkAsyncHttpClient {
76
77
private final int maxConnectionsPerEndpoint ;
77
78
private boolean isClosed = false ;
78
79
80
+ private static final Duration CRT_SDK_DEFAULT_CONNECTION_TIMEOUT = Duration .ofSeconds (3 );
81
+ // Override default connection timeout for Crt client to be in line with the CRT default:
82
+ // https://github.com/awslabs/aws-crt-java/blob/main/src/main/java/software/amazon/awssdk/crt/io/SocketOptions.java#L79
83
+ private static final AttributeMap CRT_HTTP_DEFAULTS =
84
+ AttributeMap .builder ()
85
+ .put (SdkHttpConfigurationOption .CONNECTION_TIMEOUT , CRT_SDK_DEFAULT_CONNECTION_TIMEOUT )
86
+ .build ();
87
+
79
88
private AwsCrtAsyncHttpClient (DefaultBuilder builder , AttributeMap config ) {
80
89
int maxConns = config .get (SdkHttpConfigurationOption .MAX_CONNECTIONS );
81
90
@@ -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,24 @@ 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 = NumericUtils .saturatedCast (tcpKeepAliveConfiguration .keepAliveInterval ().getSeconds ());
161
+ clientSocketOptions .keepAliveTimeoutSecs = NumericUtils .saturatedCast (tcpKeepAliveConfiguration .keepAliveTimeout ().getSeconds ());
162
+
163
+ }
164
+
165
+ return clientSocketOptions ;
166
+ }
167
+
141
168
/**
142
169
* Marks a Native CrtResource as owned by the current Java Object.
143
170
*
@@ -312,10 +339,10 @@ public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClien
312
339
Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer );
313
340
314
341
/**
315
- * Configure the health checks for for all connections established by this client.
342
+ * Configure the health checks for all connections established by this client.
316
343
*
317
344
* <p>
318
- * eg: you can set a throughput threshold for the a connection to be considered healthy.
345
+ * eg: you can set a throughput threshold for a connection to be considered healthy.
319
346
* If the connection falls below this threshold for a configurable amount of time,
320
347
* then the connection is considered unhealthy and will be shut down.
321
348
*
@@ -325,10 +352,10 @@ public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClien
325
352
Builder connectionHealthChecksConfiguration (ConnectionHealthChecksConfiguration healthChecksConfiguration );
326
353
327
354
/**
328
- * A convenience method to configure the health checks for for all connections established by this client.
355
+ * A convenience method to configure the health checks for all connections established by this client.
329
356
*
330
357
* <p>
331
- * eg: you can set a throughput threshold for the a connection to be considered healthy.
358
+ * eg: you can set a throughput threshold for a connection to be considered healthy.
332
359
* If the connection falls below this threshold for a configurable amount of time,
333
360
* then the connection is considered unhealthy and will be shut down.
334
361
*
@@ -340,9 +367,46 @@ Builder connectionHealthChecksConfiguration(Consumer<ConnectionHealthChecksConfi
340
367
healthChecksConfigurationBuilder );
341
368
342
369
/**
343
- * Configure the maximum amount of time that a connection should be allowed to remain open while idle.
370
+ * The amount of time to wait when initially establishing a connection before giving up and timing out. The maximum
371
+ * possible value, in ms, is the value of {@link Integer#MAX_VALUE}, any longer duration will be reduced to the maximum
372
+ * possible value. If not specified, the connection timeout duration will be set to value defined in
373
+ * {@link AwsCrtAsyncHttpClient#CRT_SDK_DEFAULT_CONNECTION_TIMEOUT}.
344
374
*/
345
375
Builder connectionMaxIdleTime (Duration connectionMaxIdleTime );
376
+
377
+ /**
378
+ * Configure connection socket timeout
379
+ */
380
+ Builder connectionTimeout (Duration connectionTimeout );
381
+
382
+ /**
383
+ * Configure whether to enable TCP Keep-alive and relevant configuration for all connections established by this client.
384
+ *
385
+ * <p>
386
+ * By default, keepAlive is disabled and this is not required.
387
+ * tcpKeepAlive is enabled by providing this configuration and specifying
388
+ * periodic keepalive packet intervals and timeouts
389
+ * This may be required for certain connections for longer durations than default socket timeouts
390
+ *
391
+ * @param tcpKeepAliveConfiguration The TCP keep-alive configuration to use
392
+ * @return The builder of the method chaining.
393
+ */
394
+ Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration );
395
+
396
+ /**
397
+ * Configure whether to enable TCP Keep-alive and relevant configuration for all connections established by this client.
398
+ *
399
+ * <p>
400
+ * By default, keepAlive is disabled and this is not required.
401
+ * tcpKeepAlive is enabled by providing this configuration and specifying
402
+ * periodic keepalive packet intervals and timeouts
403
+ * This may be required for certain connections for longer durations than default socket timeouts
404
+ *
405
+ * @param tcpKeepAliveConfigurationBuilder The TCP keep-alive configuration builder to use
406
+ * @return The builder of the method chaining.
407
+ */
408
+ Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
409
+ tcpKeepAliveConfigurationBuilder );
346
410
}
347
411
348
412
/**
@@ -355,20 +419,23 @@ private static final class DefaultBuilder implements Builder {
355
419
private int readBufferSize = DEFAULT_STREAM_WINDOW_SIZE ;
356
420
private ProxyConfiguration proxyConfiguration ;
357
421
private ConnectionHealthChecksConfiguration connectionHealthChecksConfiguration ;
422
+ private TcpKeepAliveConfiguration tcpKeepAliveConfiguration ;
358
423
359
424
private DefaultBuilder () {
360
425
}
361
426
362
427
@ Override
363
428
public SdkAsyncHttpClient build () {
364
429
return new AwsCrtAsyncHttpClient (this , standardOptions .build ()
430
+ .merge (CRT_HTTP_DEFAULTS )
365
431
.merge (SdkHttpConfigurationOption .GLOBAL_HTTP_DEFAULTS ));
366
432
}
367
433
368
434
@ Override
369
435
public SdkAsyncHttpClient buildWithDefaults (AttributeMap serviceDefaults ) {
370
436
return new AwsCrtAsyncHttpClient (this , standardOptions .build ()
371
437
.merge (serviceDefaults )
438
+ .merge (CRT_HTTP_DEFAULTS )
372
439
.merge (SdkHttpConfigurationOption .GLOBAL_HTTP_DEFAULTS ));
373
440
}
374
441
@@ -417,10 +484,32 @@ public Builder connectionHealthChecksConfiguration(Consumer<ConnectionHealthChec
417
484
418
485
@ Override
419
486
public Builder connectionMaxIdleTime (Duration connectionMaxIdleTime ) {
487
+ Validate .isPositive (connectionMaxIdleTime , "connectionMaxIdleTime" );
420
488
standardOptions .put (SdkHttpConfigurationOption .CONNECTION_MAX_IDLE_TIMEOUT , connectionMaxIdleTime );
421
489
return this ;
422
490
}
423
491
492
+ @ Override
493
+ public Builder connectionTimeout (Duration connectionTimeout ) {
494
+ Validate .isPositive (connectionTimeout , "connectionTimeout" );
495
+ standardOptions .put (SdkHttpConfigurationOption .CONNECTION_TIMEOUT , connectionTimeout );
496
+ return this ;
497
+ }
498
+
499
+ @ Override
500
+ public Builder tcpKeepAliveConfiguration (TcpKeepAliveConfiguration tcpKeepAliveConfiguration ) {
501
+ this .tcpKeepAliveConfiguration = tcpKeepAliveConfiguration ;
502
+ return this ;
503
+ }
504
+
505
+ @ Override
506
+ public Builder tcpKeepAliveConfiguration (Consumer <TcpKeepAliveConfiguration .Builder >
507
+ tcpKeepAliveConfigurationBuilder ) {
508
+ TcpKeepAliveConfiguration .Builder builder = TcpKeepAliveConfiguration .builder ();
509
+ tcpKeepAliveConfigurationBuilder .accept (builder );
510
+ return tcpKeepAliveConfiguration (builder .build ());
511
+ }
512
+
424
513
@ Override
425
514
public Builder proxyConfiguration (Consumer <ProxyConfiguration .Builder > proxyConfigurationBuilderConsumer ) {
426
515
ProxyConfiguration .Builder builder = ProxyConfiguration .builder ();
0 commit comments