Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
69a202c
Add connection property for connection limit
sfc-gh-ext-simba-lf Aug 20, 2025
a33320b
Add tests for new connection limit property
sfc-gh-ext-simba-lf Aug 20, 2025
ab54c06
Merge branch 'master' of https://github.com/snowflakedb/snowflake-con…
sfc-gh-ext-simba-lf Aug 20, 2025
3b789f6
Merge branch 'master' of https://github.com/snowflakedb/snowflake-con…
sfc-gh-ext-simba-lf Sep 2, 2025
51a57ba
Add value for connection limit parameter
sfc-gh-ext-simba-lf Sep 2, 2025
0129b2d
Update docs
sfc-gh-ext-simba-lf Sep 3, 2025
9c8378c
Trigger build checks
sfc-gh-ext-simba-lf Sep 5, 2025
958411b
Trigger build checks
sfc-gh-ext-simba-lf Sep 5, 2025
64e3588
Merge branch 'master' of https://github.com/snowflakedb/snowflake-con…
sfc-gh-ext-simba-lf Sep 8, 2025
046d964
Add tests for non string values
sfc-gh-ext-simba-lf Sep 12, 2025
fb095f3
Rename new property to SERVICE_POINT_CONNECTION_LIMIT
sfc-gh-ext-simba-lf Sep 12, 2025
63cfb78
Add more detail to docs about the connection limit
sfc-gh-ext-simba-lf Sep 12, 2025
3870ebc
Fix connection string
sfc-gh-ext-simba-lf Sep 16, 2025
25ba9d0
Change error thrown to SnowflakeDbException
sfc-gh-ext-simba-lf Sep 16, 2025
bf78e92
Modify tests for SnowflakeDbException
sfc-gh-ext-simba-lf Sep 16, 2025
53ad053
Modify tests for SnowflakeDbException
sfc-gh-ext-simba-lf Sep 16, 2025
22402af
Revert "Change error thrown to SnowflakeDbException"
sfc-gh-ext-simba-lf Sep 17, 2025
9bbaa19
Revert "Modify tests for SnowflakeDbException"
sfc-gh-ext-simba-lf Sep 17, 2025
d500980
Revert "Modify tests for SnowflakeDbException"
sfc-gh-ext-simba-lf Sep 17, 2025
52b2004
Validate property when parsing connection string
sfc-gh-ext-simba-lf Sep 17, 2025
53101c8
gin S
sfc-gh-ext-simba-lf Oct 7, 2025
81b029a
Rename test and add more cases
sfc-gh-ext-simba-lf Oct 16, 2025
62b0922
Modified warning log
sfc-gh-ext-simba-lf Oct 16, 2025
8ed4cca
Add upper limit for connection
sfc-gh-ext-simba-lf Oct 16, 2025
fd95018
Merge branch 'master' of https://github.com/snowflakedb/snowflake-con…
sfc-gh-ext-simba-lf Oct 21, 2025
8f516ee
Merge branch 'master' into SNOW-834807-Expose-ConnectionLimit
sfc-gh-mgemra Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
false,
false,
3,
20,
true,
CertRevocationCheckMode.Enabled.ToString(),
true,
Expand Down Expand Up @@ -57,8 +58,8 @@
var host = string.IsNullOrEmpty(testConfig.host) ? $"{testConfig.account}.snowflakecomputing.com" : testConfig.host;
var request = new HttpRequestMessage(HttpMethod.Post, $"https://{host}/queries/v1/abort-request");
var timeout = TimeSpan.FromSeconds(30);
request.Properties.Add(BaseRestRequest.HTTP_REQUEST_TIMEOUT_KEY, timeout);

Check warning on line 61 in Snowflake.Data.Tests/IntegrationTests/CertificateRevocationIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net8.0, AWS)

'HttpRequestMessage.Properties' is obsolete: 'HttpRequestMessage.Properties has been deprecated. Use Options instead.'

Check warning on line 61 in Snowflake.Data.Tests/IntegrationTests/CertificateRevocationIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net8.0, AWS)

'HttpRequestMessage.Properties' is obsolete: 'HttpRequestMessage.Properties has been deprecated. Use Options instead.'
request.Properties.Add(BaseRestRequest.REST_REQUEST_TIMEOUT_KEY, timeout);

Check warning on line 62 in Snowflake.Data.Tests/IntegrationTests/CertificateRevocationIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net8.0, AWS)

'HttpRequestMessage.Properties' is obsolete: 'HttpRequestMessage.Properties has been deprecated. Use Options instead.'

Check warning on line 62 in Snowflake.Data.Tests/IntegrationTests/CertificateRevocationIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net8.0, AWS)

'HttpRequestMessage.Properties' is obsolete: 'HttpRequestMessage.Properties has been deprecated. Use Options instead.'
return request;
}
}
Expand Down
6 changes: 4 additions & 2 deletions Snowflake.Data.Tests/UnitTests/HttpUtilTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public async Task TestNonRetryableHttpExceptionThrowsError()
.ThrowsAsync(new HttpRequestException("", new AuthenticationException()));

var httpClient = HttpUtil.Instance.GetHttpClient(
new HttpClientConfig("fakeHost", "fakePort", "user", "password", "fakeProxyList", false, false, 7, certRevocationCheckMode: "ENABLED"),
new HttpClientConfig("fakeHost", "fakePort", "user", "password", "fakeProxyList", false, false, 7, 20, certRevocationCheckMode: "ENABLED"),
handler.Object);

try
Expand Down Expand Up @@ -150,7 +150,8 @@ public void TestCreateHttpClientHandlerWithProxy()
"localhost",
false,
false,
7
7,
20
);

// act
Expand All @@ -173,6 +174,7 @@ public void TestCreateHttpClientHandlerWithoutProxy()
null,
false,
false,
20,
0
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ private HttpClientConfig GetHttpConfig(CertRevocationCheckMode checkMode = CertR
false,
false,
3,
20,
true,
checkMode.ToString(),
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,86 @@ public void TestConvertToMapOnly2Properties(
Assert.AreEqual(clientStoreTemporaryCredential, parameterMap[SFSessionParameter.CLIENT_STORE_TEMPORARY_CREDENTIAL]);
}

[Test]
[TestCase(1)]
[TestCase(10)]
[TestCase(100)]
public void TestSettingConnectionLimitProperty(int expectedConnectionLimit)
{
// arrange
var connectionString = $"ACCOUNT=account;USER=test;PASSWORD=test;SERVICE_POINT_CONNECTION_LIMIT={expectedConnectionLimit}";
var properties = SFSessionProperties.ParseConnectionString(connectionString, new SessionPropertiesContext());

// act
var extractedProperties = SFSessionHttpClientProperties.ExtractAndValidate(properties);

// assert
Assert.AreEqual(expectedConnectionLimit, extractedProperties._servicePointConnectionLimit);
}

[Test]
public void TestSettingConnectionLimitPropertyToLessThan1()
{
// arrange
var connectionString = $"ACCOUNT=account;USER=test;PASSWORD=test;SERVICE_POINT_CONNECTION_LIMIT={0}";
var properties = SFSessionProperties.ParseConnectionString(connectionString, new SessionPropertiesContext());

// act
var extractedProperties = SFSessionHttpClientProperties.ExtractAndValidate(properties);

// assert
Assert.AreEqual(SFSessionHttpClientProperties.DefaultConnectionLimit, extractedProperties._servicePointConnectionLimit);
}

[Test]
public void TestSettingConnectionLimitPropertyToGreaterThanMaxConnectionLimit()
{
// arrange
var connectionString = $"ACCOUNT=account;USER=test;PASSWORD=test;SERVICE_POINT_CONNECTION_LIMIT={SFSessionHttpClientProperties.MaxConnectionLimit + 1}";
var properties = SFSessionProperties.ParseConnectionString(connectionString, new SessionPropertiesContext());

// act
var extractedProperties = SFSessionHttpClientProperties.ExtractAndValidate(properties);

// assert
Assert.AreEqual(SFSessionHttpClientProperties.DefaultConnectionLimit, extractedProperties._servicePointConnectionLimit);
}

[Test]
public void TestSettingConnectionLimitPropertyToNoValue()
{
// arrange
var connectionString = $"ACCOUNT=account;USER=test;PASSWORD=test;SERVICE_POINT_CONNECTION_LIMIT=";
var properties = SFSessionProperties.ParseConnectionString(connectionString, new SessionPropertiesContext());

// act
var extractedProperties = SFSessionHttpClientProperties.ExtractAndValidate(properties);

// assert
Assert.AreEqual(SFSessionHttpClientProperties.DefaultConnectionLimit, extractedProperties._servicePointConnectionLimit);
}

[Test]
[TestCase("abc")]
[TestCase("1.5")]
[TestCase("true")]
[TestCase("-2.3")]
[TestCase("null")]
public void TestThrowsExceptionWhenSettingConnectionLimitPropertyToNonIntegerValue(string nonIntegerValue)
{
// arrange
var parameterName = "SERVICE_POINT_CONNECTION_LIMIT";
var expectedErrorMessage = $"Error: Invalid parameter value for {parameterName}";
var connectionString = $"ACCOUNT=account;USER=test;PASSWORD=test;{parameterName}={nonIntegerValue}";

// act
var thrown = Assert.Throws<SnowflakeDbException>(() => SFSessionProperties.ParseConnectionString(connectionString, new SessionPropertiesContext()));

// assert
Assert.AreEqual(SFError.INVALID_CONNECTION_PARAMETER_VALUE.GetAttribute<SFErrorAttr>().errorCode, thrown.ErrorCode);
Assert.IsTrue(thrown.Message.Contains(expectedErrorMessage));
}

[Test]
public void TestBuildHttpClientConfig()
{
Expand Down
12 changes: 9 additions & 3 deletions Snowflake.Data/Core/HttpUtil.cs
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public HttpClientConfig(
bool disableRetry,
bool forceRetryOn404,
int maxHttpRetries,
int connectionLimit,
bool includeRetryReason = true,
string certRevocationCheckMode = "DISABLED",
bool enableCRLDiskCaching = true,
Expand All @@ -46,6 +47,7 @@ public HttpClientConfig(
ForceRetryOn404 = forceRetryOn404;
MaxHttpRetries = maxHttpRetries;
IncludeRetryReason = includeRetryReason;
ConnectionLimit = connectionLimit;
CertRevocationCheckMode = (CertRevocationCheckMode)Enum.Parse(typeof(CertRevocationCheckMode), certRevocationCheckMode, true);
EnableCRLDiskCaching = enableCRLDiskCaching;
EnableCRLInMemoryCaching = enableCRLInMemoryCaching;
Expand All @@ -65,6 +67,7 @@ public HttpClientConfig(
forceRetryOn404.ToString(),
maxHttpRetries.ToString(),
includeRetryReason.ToString(),
connectionLimit.ToString(),
certRevocationCheckMode,
enableCRLDiskCaching.ToString(),
enableCRLInMemoryCaching.ToString(),
Expand All @@ -84,6 +87,7 @@ public HttpClientConfig(
public readonly bool ForceRetryOn404;
public readonly int MaxHttpRetries;
public readonly bool IncludeRetryReason;
public readonly int ConnectionLimit;
internal readonly CertRevocationCheckMode CertRevocationCheckMode;
internal readonly bool EnableCRLDiskCaching;
internal readonly bool EnableCRLInMemoryCaching;
Expand Down Expand Up @@ -161,7 +165,7 @@ private HttpClient RegisterNewHttpClientIfNecessary(HttpClientConfig config, Del

internal HttpClient CreateNewHttpClient(HttpClientConfig config, DelegatingHandler customHandler = null) =>
new HttpClient(
new RetryHandler(SetupCustomHttpHandler(config, customHandler), config.DisableRetry, config.ForceRetryOn404, config.MaxHttpRetries, config.IncludeRetryReason))
new RetryHandler(SetupCustomHttpHandler(config, customHandler), config.DisableRetry, config.ForceRetryOn404, config.MaxHttpRetries, config.IncludeRetryReason, config.ConnectionLimit))
{
Timeout = Timeout.InfiniteTimeSpan
};
Expand Down Expand Up @@ -434,13 +438,15 @@ private class RetryHandler : DelegatingHandler
private bool forceRetryOn404;
private int maxRetryCount;
private bool includeRetryReason;
private int connectionLimit;

internal RetryHandler(HttpMessageHandler innerHandler, bool disableRetry, bool forceRetryOn404, int maxRetryCount, bool includeRetryReason) : base(innerHandler)
internal RetryHandler(HttpMessageHandler innerHandler, bool disableRetry, bool forceRetryOn404, int maxRetryCount, bool includeRetryReason, int connectionLimit) : base(innerHandler)
{
this.disableRetry = disableRetry;
this.forceRetryOn404 = forceRetryOn404;
this.maxRetryCount = maxRetryCount;
this.includeRetryReason = includeRetryReason;
this.connectionLimit = connectionLimit;
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage,
Expand All @@ -457,7 +463,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
ServicePoint p = ServicePointManager.FindServicePoint(requestMessage.RequestUri);
p.Expect100Continue = false; // Saves about 100 ms per request
p.UseNagleAlgorithm = false; // Saves about 200 ms per request
p.ConnectionLimit = 20; // Default value is 2, we need more connections for performing multiple parallel queries
p.ConnectionLimit = connectionLimit; // Default value is 2, we need more connections for performing multiple parallel queries

TimeSpan httpTimeout = (TimeSpan)requestMessage.Properties[BaseRestRequest.HTTP_REQUEST_TIMEOUT_KEY];
TimeSpan restTimeout = (TimeSpan)requestMessage.Properties[BaseRestRequest.REST_REQUEST_TIMEOUT_KEY];
Expand Down
15 changes: 15 additions & 0 deletions Snowflake.Data/Core/Session/SFSessionHttpClientProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ internal class SFSessionHttpClientProperties
public static readonly TimeSpan DefaultExpirationTimeout = TimeSpan.FromHours(1);
public const bool DefaultPoolingEnabled = true;
public const int DefaultMaxHttpRetries = 7;
public const int DefaultConnectionLimit = 20;
public static readonly TimeSpan DefaultRetryTimeout = TimeSpan.FromSeconds(300);
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<SFSessionHttpClientProperties>();
internal static readonly int MaxConnectionLimit = 1000;

internal bool validateDefaultParameters;
internal bool clientSessionKeepAlive;
Expand All @@ -41,6 +43,7 @@ internal class SFSessionHttpClientProperties
private TimeSpan _expirationTimeout;
private bool _poolingEnabled;
internal bool _clientStoreTemporaryCredential;
internal int _servicePointConnectionLimit;
internal CertRevocationCheckMode _certRevocationCheckMode;
internal bool _enableCrlDiskCaching;
internal bool _enableCrlInMemoryCaching;
Expand Down Expand Up @@ -99,6 +102,7 @@ private void CheckPropertiesAreValid()
ValidateHttpRetries();
ValidateMinMaxPoolSize();
ValidateWaitingForSessionIdleTimeout();
ValidateConnectionLimit();
}
catch (SnowflakeDbException)
{
Expand Down Expand Up @@ -188,6 +192,15 @@ private void ValidateWaitingForSessionIdleTimeout()
}
}

private void ValidateConnectionLimit()
{
if (_servicePointConnectionLimit < 1 || _servicePointConnectionLimit > MaxConnectionLimit)
{
s_logger.Warn($"Connection limit must be between 1 and {MaxConnectionLimit}. Using the default value of {DefaultConnectionLimit}");
_servicePointConnectionLimit = DefaultConnectionLimit;
}
}

public HttpClientConfig BuildHttpClientConfig()
{
return new HttpClientConfig(
Expand All @@ -199,6 +212,7 @@ public HttpClientConfig BuildHttpClientConfig()
disableRetry,
forceRetryOn404,
maxHttpRetries,
_servicePointConnectionLimit,
includeRetryReason,
_certRevocationCheckMode.ToString(),
_enableCrlDiskCaching,
Expand Down Expand Up @@ -267,6 +281,7 @@ public SFSessionHttpClientProperties ExtractProperties(SFSessionProperties prope
_poolingEnabled = extractor.ExtractBooleanWithDefaultValue(SFSessionProperty.POOLINGENABLED),
_disableSamlUrlCheck = extractor.ExtractBooleanWithDefaultValue(SFSessionProperty.DISABLE_SAML_URL_CHECK),
_clientStoreTemporaryCredential = Boolean.Parse(propertiesDictionary[SFSessionProperty.CLIENT_STORE_TEMPORARY_CREDENTIAL]),
_servicePointConnectionLimit = int.Parse(propertiesDictionary[SFSessionProperty.SERVICE_POINT_CONNECTION_LIMIT]),
_certRevocationCheckMode = (CertRevocationCheckMode)Enum.Parse(typeof(CertRevocationCheckMode), propertiesDictionary[SFSessionProperty.CERTREVOCATIONCHECKMODE], true),
_enableCrlDiskCaching = Boolean.Parse(propertiesDictionary[SFSessionProperty.ENABLECRLDISKCACHING]),
_enableCrlInMemoryCaching = Boolean.Parse(propertiesDictionary[SFSessionProperty.ENABLECRLINMEMORYCACHING]),
Expand Down
20 changes: 20 additions & 0 deletions Snowflake.Data/Core/Session/SFSessionProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ internal enum SFSessionProperty
WORKLOAD_IDENTITY_ENTRA_RESOURCE,
[SFSessionPropertyAttr(required = false, defaultValue = "false")]
OAUTHENABLESINGLEUSEREFRESHTOKENS,
[SFSessionPropertyAttr(required = false, defaultValue = "20")]
SERVICE_POINT_CONNECTION_LIMIT,
[SFSessionPropertyAttr(required = false, defaultValue = "disabled")]
CERTREVOCATIONCHECKMODE,
[SFSessionPropertyAttr(required = false, defaultValue = "true")]
Expand Down Expand Up @@ -302,6 +304,7 @@ internal static SFSessionProperties ParseConnectionString(string connectionStrin
ValidateAccountDomain(properties);
WarnIfHttpUsed(properties);
ValidateAuthenticatorFlowsProperties(properties);
ValidateServicePointConnectionLimit(properties);
ValidateCrlParameters(properties);
ValidateTlsParameters(properties);

Expand Down Expand Up @@ -860,6 +863,23 @@ private static void ValidateFileTransferMaxBytesInMemoryProperty(SFSessionProper
}
}

private static void ValidateServicePointConnectionLimit(SFSessionProperties properties)
{
if (properties.TryGetValue(SFSessionProperty.SERVICE_POINT_CONNECTION_LIMIT, out var servicePointConnectionLimit))
{
if (!int.TryParse(servicePointConnectionLimit, out _))
{
var errorMessage = $"Invalid value of {SFSessionProperty.SERVICE_POINT_CONNECTION_LIMIT.ToString()} parameter";
logger.Error(errorMessage);
throw new SnowflakeDbException(
new Exception(errorMessage),
SFError.INVALID_CONNECTION_PARAMETER_VALUE,
"",
SFSessionProperty.SERVICE_POINT_CONNECTION_LIMIT.ToString());
}
}
}

private static bool IsRequired(SFSessionProperty sessionProperty, SFSessionProperties properties)
{
if (sessionProperty.Equals(SFSessionProperty.PASSWORD))
Expand Down
Loading
Loading