Skip to content

Commit 131783a

Browse files
committed
Updated after Zoe's comments
1 parent f0ce7cb commit 131783a

File tree

2 files changed

+22
-79
lines changed

2 files changed

+22
-79
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"type": "bugfix",
3-
"category": "Apache HTTP Client",
3+
"category": "AWS SDK for Java v2",
44
"contributor": "",
55
"description": "Fixed issue with leased connection leaks when threads executing HTTP connections with Apache HttpClient were interrupted while the connection was in progress."
66
}

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/connection/SyncClientConnectionInterruptionTest.java

Lines changed: 21 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,8 @@
3030
import java.util.concurrent.Executors;
3131
import java.util.concurrent.Future;
3232
import java.util.concurrent.atomic.AtomicLong;
33-
import java.util.stream.Stream;
3433
import org.junit.jupiter.api.BeforeEach;
3534
import org.junit.jupiter.api.Test;
36-
import org.junit.jupiter.params.ParameterizedTest;
37-
import org.junit.jupiter.params.provider.Arguments;
38-
import org.junit.jupiter.params.provider.MethodSource;
3935
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
4036
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
4137
import software.amazon.awssdk.core.exception.AbortedException;
@@ -57,8 +53,7 @@ class SyncClientConnectionInterruptionTest {
5753
public static final String SAMPLE_BODY = "{\"StringMember"
5854
+ "\":\"resultString\"}";
5955
private final WireMockServer mockServer = new WireMockServer(new WireMockConfiguration()
60-
.bindAddress("localhost")
61-
.dynamicPort());
56+
.bindAddress("localhost").dynamicPort());
6257
@BeforeEach
6358
public void setup() {
6459
mockServer.start();
@@ -67,16 +62,16 @@ public void setup() {
6762

6863
@Test
6964
void connectionPoolsGetsReusedWhenInterruptedWith_1_MaxConnection() throws Exception {
70-
Integer LONG_DELAY = 1500;
65+
Integer responseDelay = 1500;
7166

7267
String urlRegex = "/2016-03-11/allTypes";
73-
stubPostRequest(urlRegex, aResponse().withFixedDelay(LONG_DELAY), SAMPLE_BODY);
68+
stubPostRequest(urlRegex, aResponse().withFixedDelay(responseDelay), SAMPLE_BODY);
7469
SdkHttpClient httpClient = ApacheHttpClient.builder().maxConnections(1).build();
75-
ProtocolRestJsonClient client = getClient(httpClient, Duration.ofMillis(2L * LONG_DELAY)).build();
70+
ProtocolRestJsonClient client = getClient(httpClient, Duration.ofMillis(2L * responseDelay)).build();
7671

7772
ExecutorService executorService = Executors.newFixedThreadPool(5);
7873
Future<?> toBeInterruptedFuture = executorService.submit(() -> client.allTypes());
79-
unInterruptedSleep(LONG_DELAY - LONG_DELAY / 5);
74+
unInterruptedSleep(responseDelay - responseDelay / 5);
8075
toBeInterruptedFuture.cancel(true);
8176
// Make sure thread start the Http connections
8277
unInterruptedSleep(50);
@@ -85,56 +80,28 @@ void connectionPoolsGetsReusedWhenInterruptedWith_1_MaxConnection() throws Excep
8580
executorService.shutdownNow();
8681
}
8782

88-
@Test
89-
void connectionPoolsGetsReusedWhenInterruptedWith_Multiple_MaxConnection() throws Exception {
90-
Integer LONG_DELAY = 1000;
91-
Integer VERY_VERY_LONG_DELAY = LONG_DELAY * 5;
92-
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(LONG_DELAY), SAMPLE_BODY);
93-
stubPostRequest("/2016-03-11/JsonValuesOperation", aResponse().withFixedDelay(VERY_VERY_LONG_DELAY), SAMPLE_BODY);
94-
SdkHttpClient httpClient = ApacheHttpClient.builder().maxConnections(3).build();
95-
Duration timeOutDuration = Duration.ofMillis(2L * LONG_DELAY);
96-
ProtocolRestJsonClient client = getClient(httpClient, timeOutDuration).build();
97-
98-
ExecutorService executorService = Executors.newFixedThreadPool(5);
99-
Future<?> toBeInterruptedFuture0 = executorService.submit(() -> client.allTypes());
100-
Future<?> toBeInterruptedFuture1 = executorService.submit(() -> client.allTypes());
101-
Future<?> toBeInterruptedFuture2 = executorService.submit(() -> client.allTypes());
102-
unInterruptedSleep(50);
103-
executorService.submit(() -> client.jsonValuesOperation());
104-
unInterruptedSleep(LONG_DELAY / 2);
105-
toBeInterruptedFuture0.cancel(true);
106-
toBeInterruptedFuture1.cancel(true);
107-
toBeInterruptedFuture2.cancel(true);
108-
unInterruptedSleep(LONG_DELAY / 2);
109-
// Make sure thread start the Http connections
110-
AllTypesResponse allTypesResponse = client.allTypes();
111-
assertThat(allTypesResponse.stringMember()).isEqualTo("resultString");
112-
executorService.shutdownNow();
113-
}
114-
11583
@Test
11684
void interruptionWhenWaitingForLease_AbortsImmediately() throws InterruptedException {
117-
Integer LONG_DELAY = 5000;
85+
Integer responseDelay = 50000;
11886
ExceptionInThreadRun exceptionInThreadRun = new ExceptionInThreadRun();
119-
AtomicLong leaseWaitingTime = new AtomicLong(LONG_DELAY);
120-
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(LONG_DELAY), SAMPLE_BODY);
87+
AtomicLong leaseWaitingTime = new AtomicLong(responseDelay);
88+
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(responseDelay), SAMPLE_BODY);
12189
SdkHttpClient httpClient = ApacheHttpClient.builder().maxConnections(1).build();
122-
ProtocolRestJsonClient client = getClient(httpClient, Duration.ofMillis(2L * LONG_DELAY)).build();
90+
ProtocolRestJsonClient client = getClient(httpClient, Duration.ofMillis(2L * responseDelay)).build();
12391
ExecutorService executorService = Executors.newFixedThreadPool(5);
12492
executorService.submit(() -> client.allTypes());
125-
unInterruptedSleep(100);
93+
// 1 Sec sleep to make sure Thread 1 is picked for executing Http connection
94+
unInterruptedSleep(1000);
12695
Thread leaseWaitingThread = new Thread(() -> {
12796

12897
try {
12998
client.allTypes(l -> l.overrideConfiguration(
13099
b -> b
131-
.apiCallAttemptTimeout(Duration.ofSeconds(10))
132100
.addMetricPublisher(new MetricPublisher() {
133101
@Override
134102
public void publish(MetricCollection metricCollection) {
135-
System.out.println(metricCollection);
136103
Optional<MetricRecord<?>> apiCallDuration =
137-
metricCollection.stream().filter(o -> "ApiCallDuration" .equals(o.metric().name())).findAny();
104+
metricCollection.stream().filter(o -> "ApiCallDuration".equals(o.metric().name())).findAny();
138105
leaseWaitingTime.set(Duration.parse(apiCallDuration.get().value().toString()).toMillis());
139106
}
140107

@@ -151,11 +118,13 @@ public void close() {
151118
});
152119

153120
leaseWaitingThread.start();
154-
unInterruptedSleep(100);
121+
// 1 sec sleep to make sure Http connection execution is initialized for Thread 2 , in this case it will wait for lease
122+
// and immediately terminate on interrupt
123+
unInterruptedSleep(1000);
155124
leaseWaitingThread.interrupt();
156125
leaseWaitingThread.join();
157-
assertThat(leaseWaitingTime.get()).isNotEqualTo(LONG_DELAY.longValue());
158-
assertThat(leaseWaitingTime.get()).isLessThan(LONG_DELAY.longValue());
126+
assertThat(leaseWaitingTime.get()).isNotEqualTo(responseDelay.longValue());
127+
assertThat(leaseWaitingTime.get()).isLessThan(responseDelay.longValue());
159128
assertThat(exceptionInThreadRun.getException()).isInstanceOf(AbortedException.class);
160129
client.close();
161130
}
@@ -169,54 +138,28 @@ public void close() {
169138
@Test
170139
void interruptionDueToApiTimeOut_followed_byInterruptCausesOnlyTimeOutException() throws InterruptedException {
171140
SdkHttpClient httpClient = ApacheHttpClient.create();
172-
Integer SERVER_RESPONSE_DELAY = 3000;
173-
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(SERVER_RESPONSE_DELAY), SAMPLE_BODY);
141+
Integer responseDelay = 3000;
142+
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(responseDelay), SAMPLE_BODY);
174143
ExceptionInThreadRun exception = new ExceptionInThreadRun();
175144
ProtocolRestJsonClient client =
176145
getClient(httpClient, Duration.ofMillis(10)).overrideConfiguration(o -> o.retryPolicy(RetryPolicy.none())).build();
177146
unInterruptedSleep(100);
178147
// We need to creat a separate thread to interrupt it externally.
179148
Thread leaseWaitingThread = new Thread(() -> {
180149
try {
181-
client.allTypes(l -> l.overrideConfiguration(b -> b.apiCallAttemptTimeout(Duration.ofMillis(SERVER_RESPONSE_DELAY / 3))));
150+
client.allTypes(l -> l.overrideConfiguration(b -> b.apiCallAttemptTimeout(Duration.ofMillis(responseDelay / 3))));
182151
} catch (Exception e) {
183152
exception.setException(e);
184153
}
185154
});
186155
leaseWaitingThread.start();
187-
unInterruptedSleep(SERVER_RESPONSE_DELAY - SERVER_RESPONSE_DELAY / 10);
156+
unInterruptedSleep(responseDelay - responseDelay / 10);
188157
leaseWaitingThread.interrupt();
189158
leaseWaitingThread.join();
190159
assertThat(exception.getException()).isInstanceOf(ApiCallAttemptTimeoutException.class);
191160
client.close();
192161
}
193162

194-
195-
@Test
196-
void sdkClientInterrupted_while_connectionIsInProgress() throws InterruptedException {
197-
SdkHttpClient httpClient = ApacheHttpClient.create();
198-
Integer SERVER_RESPONSE_DELAY = 3000;
199-
stubPostRequest("/2016-03-11/allTypes", aResponse().withFixedDelay(SERVER_RESPONSE_DELAY), SAMPLE_BODY);
200-
ExceptionInThreadRun exception = new ExceptionInThreadRun();
201-
ProtocolRestJsonClient client =
202-
getClient(httpClient, Duration.ofMillis(10)).overrideConfiguration(o -> o.retryPolicy(RetryPolicy.none())).build();
203-
unInterruptedSleep(100);
204-
// We need to creat a separate thread to interrupt it externally.
205-
Thread leaseWaitingThread = new Thread(() -> {
206-
try {
207-
client.allTypes(l -> l.overrideConfiguration(b -> b.apiCallAttemptTimeout(Duration.ofMillis(SERVER_RESPONSE_DELAY * 3))));
208-
} catch (Exception e) {
209-
exception.setException(e);
210-
}
211-
});
212-
leaseWaitingThread.start();
213-
unInterruptedSleep(SERVER_RESPONSE_DELAY - SERVER_RESPONSE_DELAY / 10);
214-
leaseWaitingThread.interrupt();
215-
leaseWaitingThread.join();
216-
assertThat(exception.getException()).isInstanceOf(AbortedException.class);
217-
client.close();
218-
}
219-
220163
private class ExceptionInThreadRun {
221164
private Exception exception;
222165
public Exception getException() {

0 commit comments

Comments
 (0)