Skip to content

Commit f0d4459

Browse files
SNOW-1943242 JDBC Caches CloseableHttpClient Indefinitely After Connection Pool Shut Down Error (#2224)
Co-authored-by: Harry Xi <[email protected]>
1 parent 9dedf87 commit f0d4459

File tree

7 files changed

+225
-31
lines changed

7 files changed

+225
-31
lines changed

src/main/java/net/snowflake/client/core/HttpUtil.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
import org.apache.http.auth.UsernamePasswordCredentials;
4747
import org.apache.http.client.CredentialsProvider;
4848
import org.apache.http.client.config.RequestConfig;
49-
import org.apache.http.client.methods.CloseableHttpResponse;
5049
import org.apache.http.client.methods.HttpRequestBase;
5150
import org.apache.http.config.Registry;
5251
import org.apache.http.config.RegistryBuilder;
@@ -745,7 +744,10 @@ static String executeRequestWithoutCookies(
745744
getHttpClient(ocspAndProxyKey, null),
746745
new ExecTimeTelemetryData(),
747746
null,
748-
sfSession);
747+
sfSession,
748+
ocspAndProxyKey,
749+
null,
750+
false);
749751
}
750752

751753
/**
@@ -842,7 +844,10 @@ public static String executeGeneralRequestOmitRequestGuid(
842844
getHttpClient(ocspAndProxyAndGzipKey, null),
843845
new ExecTimeTelemetryData(),
844846
null,
845-
sfSession);
847+
sfSession,
848+
ocspAndProxyAndGzipKey,
849+
null,
850+
false);
846851
}
847852

848853
/**
@@ -957,7 +962,10 @@ public static String executeGeneralRequest(
957962
httpClient,
958963
new ExecTimeTelemetryData(),
959964
null,
960-
sfSession);
965+
sfSession,
966+
null,
967+
null,
968+
false);
961969
}
962970

963971
/**
@@ -1161,7 +1169,10 @@ public static String executeRequest(
11611169
getHttpClient(ocspAndProxyKey, null),
11621170
execTimeData,
11631171
retryContextManager,
1164-
sfSession);
1172+
sfSession,
1173+
ocspAndProxyKey,
1174+
null,
1175+
false);
11651176
}
11661177

11671178
/**
@@ -1185,6 +1196,10 @@ public static String executeRequest(
11851196
* @param httpClient client object used to communicate with other machine
11861197
* @param retryContextManager RetryContext used to customize retry handling functionality
11871198
* @param sfSession the session associated with the request
1199+
* @param key HttpClientSettingsKey object
1200+
* @param httpHeaderCustomizer HttpHeadersCustomizer object for customization of HTTP headers for
1201+
* requests sent by the Snowflake JDBC driver.
1202+
* @param isHttpClientWithoutDecompression flag for create client without Decompression
11881203
* @return response in String
11891204
* @throws SnowflakeSQLException if Snowflake error occurs
11901205
* @throws IOException raises if a general IO error occurs
@@ -1204,15 +1219,17 @@ private static String executeRequestInternal(
12041219
CloseableHttpClient httpClient,
12051220
ExecTimeTelemetryData execTimeData,
12061221
RetryContextManager retryContextManager,
1207-
SFBaseSession sfSession)
1222+
SFBaseSession sfSession,
1223+
HttpClientSettingsKey key,
1224+
List<HttpHeadersCustomizer> httpHeaderCustomizer,
1225+
boolean isHttpClientWithoutDecompression)
12081226
throws SnowflakeSQLException, IOException {
12091227
String requestInfoScrubbed = SecretDetector.maskSASToken(httpRequest.toString());
12101228
String responseText = "";
12111229

12121230
logger.debug(
12131231
"Pool: {} Executing: {}", (ArgSupplier) HttpUtil::getHttpClientStats, requestInfoScrubbed);
12141232

1215-
CloseableHttpResponse response = null;
12161233
Stopwatch stopwatch = null;
12171234

12181235
String requestIdStr = URLUtil.getRequestIdLogStr(httpRequest.getURI());
@@ -1235,7 +1252,14 @@ private static String executeRequestInternal(
12351252
.build();
12361253
responseText =
12371254
RestRequest.executeWithRetries(
1238-
httpClient, httpRequest, context, execTimeData, retryContextManager)
1255+
httpClient,
1256+
httpRequest,
1257+
context,
1258+
execTimeData,
1259+
retryContextManager,
1260+
key,
1261+
httpHeaderCustomizer,
1262+
isHttpClientWithoutDecompression)
12391263
.getUnpackedCloseableHttpResponse();
12401264

12411265
logger.debug(

src/main/java/net/snowflake/client/jdbc/DefaultResultStreamProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ else if (context.getQrmk() != null) {
148148
true, // no retry on http request
149149
false,
150150
new ExecTimeTelemetryData(),
151-
session)
151+
session,
152+
context.getChunkDownloader().getHttpClientSettingsKey(),
153+
headersCustomizers,
154+
false)
152155
.getHttpResponse();
153156

154157
logger.debug(

src/main/java/net/snowflake/client/jdbc/RestRequest.java

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import net.snowflake.client.core.Event;
2525
import net.snowflake.client.core.EventUtil;
2626
import net.snowflake.client.core.ExecTimeTelemetryData;
27+
import net.snowflake.client.core.HttpClientSettingsKey;
2728
import net.snowflake.client.core.HttpExecutingContext;
2829
import net.snowflake.client.core.HttpExecutingContextBuilder;
2930
import net.snowflake.client.core.HttpResponseContextDto;
@@ -197,7 +198,10 @@ public static CloseableHttpResponse execute(
197198
false, // noRetry
198199
execTimeTelemetryData,
199200
null,
200-
sfSession);
201+
sfSession,
202+
null,
203+
null,
204+
false);
201205
}
202206

203207
/**
@@ -312,7 +316,10 @@ public static CloseableHttpResponse execute(
312316
noRetry,
313317
execTimeData,
314318
null,
315-
sfSession);
319+
sfSession,
320+
null,
321+
null,
322+
false);
316323
}
317324

318325
/**
@@ -427,7 +434,10 @@ public static CloseableHttpResponse execute(
427434
false, // noRetry
428435
execTimeData,
429436
retryContextManager,
430-
sfSession);
437+
sfSession,
438+
null,
439+
null,
440+
false);
431441
}
432442

433443
/**
@@ -488,9 +498,11 @@ public static CloseableHttpResponse execute(
488498
noRetry,
489499
execTimeData,
490500
retryManager,
491-
null);
501+
null,
502+
null,
503+
null,
504+
false);
492505
}
493-
494506
/**
495507
* Execute an HTTP request with retry logic.
496508
*
@@ -512,6 +524,10 @@ public static CloseableHttpResponse execute(
512524
* @param retryManager RetryContextManager - object allowing to optionally pass custom logic that
513525
* should be executed before and/or after the retry
514526
* @param sfSession the session associated with the request
527+
* @param key HttpClientSettingsKey object
528+
* @param httpHeaderCustomizer HttpHeadersCustomizer object for customization of HTTP headers for
529+
* requests sent by the Snowflake JDBC driver.
530+
* @param isHttpClientWithoutDecompression flag for create client without Decompression
515531
* @return HttpResponse Object get from server
516532
* @throws net.snowflake.client.jdbc.SnowflakeSQLException Request timeout Exception or Illegal
517533
* State Exception i.e. connection is already shutdown etc
@@ -533,7 +549,10 @@ public static CloseableHttpResponse execute(
533549
boolean noRetry,
534550
ExecTimeTelemetryData execTimeData,
535551
RetryContextManager retryManager,
536-
SFBaseSession sfSession)
552+
SFBaseSession sfSession,
553+
HttpClientSettingsKey key,
554+
List<HttpHeadersCustomizer> httpHeaderCustomizer,
555+
boolean isHttpClientWithoutDecompression)
537556
throws SnowflakeSQLException {
538557
return executeWithRetries(
539558
httpClient,
@@ -550,7 +569,10 @@ public static CloseableHttpResponse execute(
550569
retryHTTP403, // retry on HTTP 403
551570
noRetry,
552571
new ExecTimeTelemetryData(),
553-
sfSession)
572+
sfSession,
573+
key,
574+
httpHeaderCustomizer,
575+
isHttpClientWithoutDecompression)
554576
.getHttpResponse();
555577
}
556578

@@ -738,7 +760,10 @@ public static HttpResponseContextDto executeWithRetries(
738760
boolean retryHTTP403,
739761
boolean unpackResponse,
740762
ExecTimeTelemetryData execTimeTelemetryData,
741-
SFBaseSession sfSession)
763+
SFBaseSession sfSession,
764+
HttpClientSettingsKey key,
765+
List<HttpHeadersCustomizer> httpHeaderCustomizer,
766+
boolean isHttpClientWithoutDecompression)
742767
throws SnowflakeSQLException {
743768
return executeWithRetries(
744769
httpClient,
@@ -756,7 +781,10 @@ public static HttpResponseContextDto executeWithRetries(
756781
false,
757782
unpackResponse,
758783
execTimeTelemetryData,
759-
sfSession);
784+
sfSession,
785+
key,
786+
httpHeaderCustomizer,
787+
isHttpClientWithoutDecompression);
760788
}
761789

762790
/**
@@ -799,7 +827,10 @@ public static HttpResponseContextDto executeWithRetries(
799827
boolean noRetry,
800828
boolean unpackResponse,
801829
ExecTimeTelemetryData execTimeTelemetryData,
802-
SFBaseSession sfSession)
830+
SFBaseSession sfSession,
831+
HttpClientSettingsKey key,
832+
List<HttpHeadersCustomizer> httpHeaderCustomizer,
833+
boolean isHttpClientWithoutDecompression)
803834
throws SnowflakeSQLException {
804835
String requestIdStr = URLUtil.getRequestIdLogStr(httpRequest.getURI());
805836
String requestInfoScrubbed = SecretDetector.maskSASToken(httpRequest.toString());
@@ -820,7 +851,15 @@ public static HttpResponseContextDto executeWithRetries(
820851
.loginRequest(SessionUtil.isNewRetryStrategyRequest(httpRequest))
821852
.withSfSession(sfSession)
822853
.build();
823-
return executeWithRetries(httpClient, httpRequest, context, execTimeTelemetryData, null);
854+
return executeWithRetries(
855+
httpClient,
856+
httpRequest,
857+
context,
858+
execTimeTelemetryData,
859+
null,
860+
key,
861+
httpHeaderCustomizer,
862+
isHttpClientWithoutDecompression);
824863
}
825864

826865
/**
@@ -840,7 +879,10 @@ public static HttpResponseContextDto executeWithRetries(
840879
HttpRequestBase httpRequest,
841880
HttpExecutingContext httpExecutingContext,
842881
ExecTimeTelemetryData execTimeData,
843-
RetryContextManager retryManager)
882+
RetryContextManager retryManager,
883+
HttpClientSettingsKey key,
884+
List<HttpHeadersCustomizer> httpHeaderCustomizer,
885+
boolean isHttpClientWithoutDecompression)
844886
throws SnowflakeSQLException {
845887
Stopwatch networkComunnicationStapwatch = null;
846888
Stopwatch requestReponseStopWatch = null;
@@ -908,7 +950,26 @@ public static HttpResponseContextDto executeWithRetries(
908950
responseDto.setHttpResponse(response);
909951
execTimeData.setHttpClientEnd();
910952
} catch (Exception ex) {
911-
responseDto.setSavedEx(handlingNotRetryableException(ex, httpExecutingContext));
953+
if (ex instanceof IllegalStateException) {
954+
// if exception is caused by illegal state, e.g shutdown of http client
955+
// because of closing of connection, then recreate the http client and remove existing
956+
// from the cache.
957+
logger.warn(
958+
"IllegalStateException encountered while processing the HTTP request."
959+
+ " The HttpClient was shut down due to connection closure. "
960+
+ "Attempting to rebuild the HttpClient and retry the request.");
961+
// Clear the httpClient cache.
962+
HttpUtil.httpClient.remove(key);
963+
// rebuild the http client.
964+
if (isHttpClientWithoutDecompression) {
965+
httpClient = HttpUtil.getHttpClientWithoutDecompression(key, httpHeaderCustomizer);
966+
} else {
967+
httpClient = HttpUtil.getHttpClient(key, httpHeaderCustomizer);
968+
}
969+
continue;
970+
} else {
971+
responseDto.setSavedEx(handlingNotRetryableException(ex, httpExecutingContext));
972+
}
912973
} finally {
913974
// Reset the socket timeout to its original value if it is not the
914975
// very first iteration.

src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,10 @@ public void download(
254254
true, // retry on HTTP 403
255255
false,
256256
new ExecTimeTelemetryData(),
257-
session);
257+
session,
258+
session.getHttpClientKey(),
259+
session.getHttpHeadersCustomizers(),
260+
true);
258261
HttpResponse response = responseDto.getHttpResponse();
259262

260263
logger.debug(
@@ -446,7 +449,10 @@ public InputStream downloadToStream(
446449
true, // retry on HTTP 403
447450
false,
448451
new ExecTimeTelemetryData(),
449-
session)
452+
session,
453+
session.getHttpClientKey(),
454+
session.getHttpHeadersCustomizers(),
455+
true)
450456
.getHttpResponse();
451457

452458
logger.debug(
@@ -943,7 +949,10 @@ private void uploadWithPresignedUrl(
943949
true, // retry on HTTP 403
944950
true, // disable retry
945951
new ExecTimeTelemetryData(),
946-
session)
952+
session,
953+
ocspAndProxyKey,
954+
session.getHttpHeadersCustomizers(),
955+
false)
947956
.getHttpResponse();
948957

949958
logger.debug(

src/test/java/net/snowflake/client/jdbc/ChunkDownloaderS3RetryUrlLatestIT.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ public void testParamsInRetryS3Url() throws Exception {
8383
true,
8484
false,
8585
new ExecTimeTelemetryData(),
86-
null); // retry HTTP 403
86+
null, // retry HTTP 403
87+
sfContext.getChunkDownloader().getHttpClientSettingsKey(),
88+
null,
89+
false);
8790

8891
assertFalse(getRequest.containsHeader("retryCount"));
8992
assertFalse(getRequest.containsHeader("retryReason"));

0 commit comments

Comments
 (0)