Skip to content

Commit 84b1777

Browse files
SNOW-1020043: Configure connection and socket timeout (#1628)
1 parent 35edeea commit 84b1777

File tree

10 files changed

+142
-45
lines changed

10 files changed

+142
-45
lines changed

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

+32-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.net.Socket;
2121
import java.security.KeyManagementException;
2222
import java.security.NoSuchAlgorithmException;
23+
import java.time.Duration;
2324
import java.util.Map;
2425
import java.util.Properties;
2526
import java.util.concurrent.ConcurrentHashMap;
@@ -59,23 +60,27 @@
5960
import org.apache.http.util.EntityUtils;
6061

6162
public class HttpUtil {
62-
static final SFLogger logger = SFLoggerFactory.getLogger(HttpUtil.class);
63+
private static final SFLogger logger = SFLoggerFactory.getLogger(HttpUtil.class);
6364

6465
static final int DEFAULT_MAX_CONNECTIONS = 300;
6566
static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 300;
66-
static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
67-
static final int DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT = 300000; // ms
67+
private static final int DEFAULT_HTTP_CLIENT_CONNECTION_TIMEOUT_IN_MS = 60000;
68+
static final int DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT_IN_MS = 300000; // ms
6869
static final int DEFAULT_TTL = 60; // secs
6970
static final int DEFAULT_IDLE_CONNECTION_TIMEOUT = 5; // secs
7071
static final int DEFAULT_DOWNLOADED_CONDITION_TIMEOUT = 3600; // secs
7172

7273
public static final String JDBC_TTL = "net.snowflake.jdbc.ttl";
74+
static final String JDBC_CONNECTION_TIMEOUT_IN_MS_PROPERTY =
75+
"net.snowflake.jdbc.http_client_connection_timeout_in_ms";
76+
static final String JDBC_SOCKET_TIMEOUT_IN_MS_PROPERTY =
77+
"net.snowflake.jdbc.http_client_socket_timeout_in_ms";
7378
public static final String JDBC_MAX_CONNECTIONS_PROPERTY = "net.snowflake.jdbc.max_connections";
7479
public static final String JDBC_MAX_CONNECTIONS_PER_ROUTE_PROPERTY =
7580
"net.snowflake.jdbc.max_connections_per_route";
7681

7782
/**
78-
* The unique httpClient shared by all connections. This will benefit long- lived clients. Key =
83+
* The unique httpClient shared by all connections. This will benefit long-lived clients. Key =
7984
* proxy host + proxy port + nonProxyHosts, Value = Map of [OCSPMode, HttpClient]
8085
*/
8186
public static Map<HttpClientSettingsKey, CloseableHttpClient> httpClient =
@@ -101,6 +106,20 @@ public class HttpUtil {
101106

102107
private static boolean socksProxyDisabled = false;
103108

109+
@SnowflakeJdbcInternalApi
110+
public static Duration getConnectionTimeout() {
111+
return Duration.ofMillis(
112+
convertSystemPropertyToIntValue(
113+
JDBC_CONNECTION_TIMEOUT_IN_MS_PROPERTY, DEFAULT_HTTP_CLIENT_CONNECTION_TIMEOUT_IN_MS));
114+
}
115+
116+
@SnowflakeJdbcInternalApi
117+
public static Duration getSocketTimeout() {
118+
return Duration.ofMillis(
119+
convertSystemPropertyToIntValue(
120+
JDBC_SOCKET_TIMEOUT_IN_MS_PROPERTY, DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT_IN_MS));
121+
}
122+
104123
public static long getDownloadedConditionTimeoutInSeconds() {
105124
return DEFAULT_DOWNLOADED_CONDITION_TIMEOUT;
106125
}
@@ -286,9 +305,14 @@ public static CloseableHttpClient buildHttpClient(
286305
@Nullable HttpClientSettingsKey key, File ocspCacheFile, boolean downloadUnCompressed) {
287306
// set timeout so that we don't wait forever.
288307
// Setup the default configuration for all requests on this client
289-
290308
int timeToLive = convertSystemPropertyToIntValue(JDBC_TTL, DEFAULT_TTL);
291309
logger.debug("time to live in connection pooling manager: {}", timeToLive);
310+
long connectTimeout = getConnectionTimeout().toMillis();
311+
long socketTimeout = getSocketTimeout().toMillis();
312+
logger.debug(
313+
"Connect timeout is {} ms and socket timeout is {} for connection pooling manager",
314+
connectTimeout,
315+
socketTimeout);
292316

293317
// Set proxy settings for DefaultRequestConfig. If current proxy settings are the same as for
294318
// the last request, keep the current DefaultRequestConfig. If not, build a new
@@ -306,9 +330,9 @@ public static CloseableHttpClient buildHttpClient(
306330
if (noDefaultRequestConfig || !DefaultRequestConfig.getProxy().equals(proxy)) {
307331
RequestConfig.Builder builder =
308332
RequestConfig.custom()
309-
.setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT)
310-
.setConnectionRequestTimeout(DEFAULT_CONNECTION_TIMEOUT)
311-
.setSocketTimeout(DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT);
333+
.setConnectTimeout((int) connectTimeout)
334+
.setConnectionRequestTimeout((int) connectTimeout)
335+
.setSocketTimeout((int) socketTimeout);
312336
// only set the proxy settings if they are not null
313337
// but no value has been specified for nonProxyHosts
314338
// the route planner will determine whether to use a proxy based on nonProxyHosts value.

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

+8-10
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
import java.net.MalformedURLException;
88
import java.net.URL;
99
import java.security.PrivateKey;
10+
import java.time.Duration;
1011
import java.util.Map;
1112
import net.snowflake.client.jdbc.ErrorCode;
1213

1314
/** A class for holding all information required for login */
1415
public class SFLoginInput {
15-
private static int DEFAULT_HTTP_CLIENT_CONNECTION_TIMEOUT = 60000; // millisec
16-
private static int DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT = 300000; // millisec
17-
1816
private String serverUrl;
1917
private String databaseName;
2018
private String schemaName;
@@ -32,8 +30,8 @@ public class SFLoginInput {
3230
private boolean passcodeInPassword;
3331
private String passcode;
3432
private String token;
35-
private int connectionTimeout = DEFAULT_HTTP_CLIENT_CONNECTION_TIMEOUT;
36-
private int socketTimeout = DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT;
33+
private Duration connectionTimeout = HttpUtil.getConnectionTimeout();
34+
private Duration socketTimeout = HttpUtil.getSocketTimeout();
3735
private String appId;
3836
private String appVersion;
3937
private String sessionToken;
@@ -216,20 +214,20 @@ public SFLoginInput setToken(String token) {
216214
return this;
217215
}
218216

219-
int getConnectionTimeout() {
217+
Duration getConnectionTimeout() {
220218
return connectionTimeout;
221219
}
222220

223-
SFLoginInput setConnectionTimeout(int connectionTimeout) {
221+
SFLoginInput setConnectionTimeout(Duration connectionTimeout) {
224222
this.connectionTimeout = connectionTimeout;
225223
return this;
226224
}
227225

228-
int getSocketTimeout() {
229-
return socketTimeout;
226+
int getSocketTimeoutInMillis() {
227+
return (int) socketTimeout.toMillis();
230228
}
231229

232-
SFLoginInput setSocketTimeout(int socketTimeout) {
230+
SFLoginInput setSocketTimeout(Duration socketTimeout) {
233231
this.socketTimeout = socketTimeout;
234232
return this;
235233
}

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package net.snowflake.client.core;
66

7+
import java.time.Duration;
78
import java.util.Map;
89

910
/** Login output information including session tokens, database versions */
@@ -16,7 +17,7 @@ public class SFLoginOutput {
1617
private String databaseVersion;
1718
private int databaseMajorVersion;
1819
private int databaseMinorVersion;
19-
private int httpClientSocketTimeout;
20+
private Duration httpClientSocketTimeout;
2021
private String sessionDatabase;
2122
private String sessionSchema;
2223
private String sessionRole;
@@ -50,7 +51,7 @@ public class SFLoginOutput {
5051
this.databaseVersion = databaseVersion;
5152
this.databaseMajorVersion = databaseMajorVersion;
5253
this.databaseMinorVersion = databaseMinorVersion;
53-
this.httpClientSocketTimeout = httpClientSocketTimeout;
54+
this.httpClientSocketTimeout = Duration.ofMillis(httpClientSocketTimeout);
5455
this.sessionDatabase = sessionDatabase;
5556
this.sessionSchema = sessionSchema;
5657
this.sessionRole = sessionRole;
@@ -106,7 +107,7 @@ int getDatabaseMinorVersion() {
106107
return databaseMinorVersion;
107108
}
108109

109-
int getHttpClientSocketTimeout() {
110+
Duration getHttpClientSocketTimeout() {
110111
return httpClientSocketTimeout;
111112
}
112113

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

+15-7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.security.PrivateKey;
1515
import java.sql.DriverPropertyInfo;
1616
import java.sql.SQLException;
17+
import java.time.Duration;
1718
import java.util.*;
1819
import java.util.concurrent.*;
1920
import java.util.concurrent.atomic.AtomicInteger;
@@ -48,7 +49,9 @@ public class SFSession extends SFBaseSession {
4849
"CLIENT_STORE_TEMPORARY_CREDENTIAL";
4950
private static final ObjectMapper mapper = ObjectMapperFactory.getObjectMapper();
5051
private static final int MAX_SESSION_PARAMETERS = 1000;
51-
public static final int DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT = 300000; // millisec
52+
// this constant was public - let's not change it
53+
public static final int DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT =
54+
HttpUtil.DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT_IN_MS;
5255
private final AtomicInteger sequenceId = new AtomicInteger(0);
5356
private final List<DriverPropertyInfo> missingProperties = new ArrayList<>();
5457
// list of active asynchronous queries. Used to see if session should be closed when connection
@@ -85,8 +88,8 @@ public class SFSession extends SFBaseSession {
8588

8689
private int authTimeout = 0;
8790
private boolean enableCombineDescribe = false;
88-
private int httpClientConnectionTimeout = 60000; // milliseconds
89-
private int httpClientSocketTimeout = DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT; // milliseconds
91+
private final Duration httpClientConnectionTimeout = HttpUtil.getConnectionTimeout();
92+
private Duration httpClientSocketTimeout = HttpUtil.getSocketTimeout();
9093
// whether we try to simulate a socket timeout (a default value of 0 means
9194
// no simulation). The value is in milliseconds
9295
private int injectSocketTimeout = 0;
@@ -188,7 +191,12 @@ private JsonNode getQueryMetadata(String queryID) throws SQLException {
188191
get.setHeader("Authorization", "Snowflake Token=\"" + this.sessionToken + "\"");
189192
response =
190193
HttpUtil.executeGeneralRequest(
191-
get, loginTimeout, authTimeout, httpClientSocketTimeout, 0, getHttpClientKey());
194+
get,
195+
loginTimeout,
196+
authTimeout,
197+
(int) httpClientSocketTimeout.toMillis(),
198+
0,
199+
getHttpClientKey());
192200
jsonNode = OBJECT_MAPPER.readTree(response);
193201
} catch (Exception e) {
194202
throw new SnowflakeSQLLoggedException(
@@ -915,7 +923,7 @@ protected void heartbeat() throws SFException, SQLException {
915923
postRequest,
916924
SF_HEARTBEAT_TIMEOUT,
917925
authTimeout,
918-
httpClientSocketTimeout,
926+
(int) httpClientSocketTimeout.toMillis(),
919927
0,
920928
getHttpClientKey());
921929

@@ -985,11 +993,11 @@ public int getAuthTimeout() {
985993
}
986994

987995
public int getHttpClientSocketTimeout() {
988-
return httpClientSocketTimeout;
996+
return (int) httpClientSocketTimeout.toMillis();
989997
}
990998

991999
public int getHttpClientConnectionTimeout() {
992-
return httpClientConnectionTimeout;
1000+
return (int) httpClientConnectionTimeout.toMillis();
9931001
}
9941002

9951003
public boolean isClosed() {

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

+11-11
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ private static SFLoginOutput newSession(
354354
int databaseMinorVersion = 0;
355355
String newClientForUpgrade;
356356
int healthCheckInterval = DEFAULT_HEALTH_CHECK_INTERVAL;
357-
int httpClientSocketTimeout = loginInput.getSocketTimeout();
357+
int httpClientSocketTimeout = loginInput.getSocketTimeoutInMillis();
358358
final ClientAuthnDTO.AuthenticatorType authenticatorType = getAuthenticator(loginInput);
359359
Map<String, Object> commonParams;
360360

@@ -623,7 +623,7 @@ private static SFLoginOutput newSession(
623623
String theString = null;
624624

625625
int leftRetryTimeout = loginInput.getLoginTimeout();
626-
int leftsocketTimeout = loginInput.getSocketTimeout();
626+
int leftsocketTimeout = loginInput.getSocketTimeoutInMillis();
627627
int retryCount = 0;
628628

629629
while (true) {
@@ -664,7 +664,7 @@ private static SFLoginOutput newSession(
664664
// auth timeout within socket timeout is thrown without backoff,
665665
// and we need to update time remained in socket timeout here to control the
666666
// the actual socket timeout from customer setting.
667-
if (loginInput.getSocketTimeout() > 0) {
667+
if (loginInput.getSocketTimeoutInMillis() > 0) {
668668
if (ex.issocketTimeoutNoBackoff()) {
669669
if (leftsocketTimeout > elapsedSeconds) {
670670
leftsocketTimeout -= elapsedSeconds;
@@ -673,7 +673,7 @@ private static SFLoginOutput newSession(
673673
}
674674
} else {
675675
// reset curl timeout for retry with backoff.
676-
leftsocketTimeout = loginInput.getSocketTimeout();
676+
leftsocketTimeout = loginInput.getSocketTimeoutInMillis();
677677
}
678678
}
679679

@@ -782,11 +782,11 @@ private static SFLoginOutput newSession(
782782
if (healthCheckIntervalFromGS > 0 && healthCheckIntervalFromGS != healthCheckInterval) {
783783
// add health check interval to socket timeout
784784
httpClientSocketTimeout =
785-
loginInput.getSocketTimeout() + (healthCheckIntervalFromGS * 1000);
785+
loginInput.getSocketTimeoutInMillis() + (healthCheckIntervalFromGS * 1000);
786786

787787
final RequestConfig requestConfig =
788788
RequestConfig.copy(HttpUtil.getRequestConfigWithoutCookies())
789-
.setConnectTimeout(loginInput.getConnectionTimeout())
789+
.setConnectTimeout((int) loginInput.getConnectionTimeout().toMillis())
790790
.setSocketTimeout(httpClientSocketTimeout)
791791
.build();
792792

@@ -961,7 +961,7 @@ private static SFLoginOutput tokenRequest(SFLoginInput loginInput, TokenRequestT
961961
postRequest,
962962
loginInput.getLoginTimeout(),
963963
loginInput.getAuthTimeout(),
964-
loginInput.getSocketTimeout(),
964+
loginInput.getSocketTimeoutInMillis(),
965965
0,
966966
loginInput.getHttpClientSettingsKey());
967967

@@ -1054,7 +1054,7 @@ static void closeSession(SFLoginInput loginInput) throws SFException, SnowflakeS
10541054
postRequest,
10551055
loginInput.getLoginTimeout(),
10561056
loginInput.getAuthTimeout(),
1057-
loginInput.getSocketTimeout(),
1057+
loginInput.getSocketTimeoutInMillis(),
10581058
0,
10591059
loginInput.getHttpClientSettingsKey());
10601060

@@ -1120,7 +1120,7 @@ private static String federatedFlowStep4(
11201120
httpGet,
11211121
loginInput.getLoginTimeout(),
11221122
loginInput.getAuthTimeout(),
1123-
loginInput.getSocketTimeout(),
1123+
loginInput.getSocketTimeoutInMillis(),
11241124
0,
11251125
loginInput.getHttpClientSettingsKey());
11261126

@@ -1194,7 +1194,7 @@ private static String federatedFlowStep3(SFLoginInput loginInput, String tokenUr
11941194
postRequest,
11951195
loginInput.getLoginTimeout(),
11961196
loginInput.getAuthTimeout(),
1197-
loginInput.getSocketTimeout(),
1197+
loginInput.getSocketTimeoutInMillis(),
11981198
0,
11991199
0,
12001200
null,
@@ -1285,7 +1285,7 @@ private static JsonNode federatedFlowStep1(SFLoginInput loginInput) throws Snowf
12851285
postRequest,
12861286
loginInput.getLoginTimeout(),
12871287
loginInput.getAuthTimeout(),
1288-
loginInput.getSocketTimeout(),
1288+
loginInput.getSocketTimeoutInMillis(),
12891289
0,
12901290
loginInput.getHttpClientSettingsKey());
12911291
logger.debug("authenticator-request response: {}", gsResponse);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ private String getSSOUrl(int port) throws SFException, SnowflakeSQLException {
187187
postRequest,
188188
loginInput.getLoginTimeout(),
189189
loginInput.getAuthTimeout(),
190-
loginInput.getSocketTimeout(),
190+
loginInput.getSocketTimeoutInMillis(),
191191
0,
192192
loginInput.getHttpClientSettingsKey());
193193

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ public static CloseableHttpResponse execute(
242242

243243
savedEx = ex;
244244
// if the request took more than 5 min (socket timeout) log an error
245-
if ((System.currentTimeMillis() - startTimePerRequest) > 300000) {
245+
if ((System.currentTimeMillis() - startTimePerRequest)
246+
> HttpUtil.getSocketTimeout().toMillis()) {
246247
logger.warn(
247248
"HTTP request took longer than 5 min: {} sec",
248249
(System.currentTimeMillis() - startTimePerRequest) / 1000);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,7 @@ public void uploadWithPresignedUrlWithoutConnection(
584584
uploadWithPresignedUrl(
585585
networkTimeoutInMilli,
586586
0, // auth timeout
587-
SFSession.DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT, // socket timeout
587+
(int) HttpUtil.getSocketTimeout().toMillis(),
588588
meta.getContentEncoding(),
589589
meta.getUserMetadata(),
590590
uploadStreamInfo.left,

src/main/java/net/snowflake/client/jdbc/telemetry/TelemetryClient.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
*/
44
package net.snowflake.client.jdbc.telemetry;
55

6-
import static net.snowflake.client.core.SFSession.DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT;
7-
86
import com.fasterxml.jackson.databind.ObjectMapper;
97
import com.fasterxml.jackson.databind.node.ArrayNode;
108
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -361,7 +359,7 @@ private boolean sendBatch() throws IOException {
361359
post,
362360
TELEMETRY_HTTP_RETRY_TIMEOUT_IN_SEC,
363361
0,
364-
DEFAULT_HTTP_CLIENT_SOCKET_TIMEOUT,
362+
(int) HttpUtil.getSocketTimeout().toMillis(),
365363
0,
366364
this.httpClient)
367365
: HttpUtil.executeGeneralRequest(

0 commit comments

Comments
 (0)