From f89504c75d7e1dffb0501e4e14a202f932772256 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Wed, 16 Jul 2025 18:35:36 +0300 Subject: [PATCH 1/4] dev: MinSessionPool, SessionIdleTimeout, SessionPruningInterval --- src/Ydb.Sdk/CHANGELOG.md | 4 + .../src/Ado/YdbConnectionStringBuilder.cs | 76 +++++++++++++++++-- .../YdbConnectionStringBuilderTests.cs | 22 ++++-- 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/Ydb.Sdk/CHANGELOG.md b/src/Ydb.Sdk/CHANGELOG.md index a4d7e72a..86cad751 100644 --- a/src/Ydb.Sdk/CHANGELOG.md +++ b/src/Ydb.Sdk/CHANGELOG.md @@ -1,3 +1,7 @@ +- Added new ADO.NET options: + - `MinSessionPool`: The minimum connection pool size. + - `SessionIdleTimeout`: The time (in seconds) to wait before closing idle session in the pool if the count of all connections exceeds `MinSessionPool`. + - `SessionPruningInterval`: How many seconds the pool waits before attempting to prune idle sessions (see `SessionIdleTimeout`). - Fixed bug `Reader`: unhandled exception in `TryReadRequestBytes(long bytes)`. - Handle `YdbException` on `DeleteSession`. - Do not invoke `DeleteSession` if the session is not active. diff --git a/src/Ydb.Sdk/src/Ado/YdbConnectionStringBuilder.cs b/src/Ydb.Sdk/src/Ado/YdbConnectionStringBuilder.cs index 669c2bf1..68c5849f 100644 --- a/src/Ydb.Sdk/src/Ado/YdbConnectionStringBuilder.cs +++ b/src/Ydb.Sdk/src/Ado/YdbConnectionStringBuilder.cs @@ -28,7 +28,11 @@ private void InitDefaultValues() _host = YdbAdoDefaultSettings.Host; _port = YdbAdoDefaultSettings.Port; _database = YdbAdoDefaultSettings.Database; + _minSessionPool = 0; _maxSessionPool = SessionPoolDefaultSettings.MaxSessionPool; + _createSessionTimeout = SessionPoolDefaultSettings.CreateSessionTimeoutSeconds; + _sessionIdleTimeout = 300; + _sessionPruningInterval = 10; _useTls = YdbAdoDefaultSettings.UseTls; _connectTimeout = GrpcDefaultSettings.ConnectTimeoutSeconds; _keepAlivePingDelay = GrpcDefaultSettings.KeepAlivePingSeconds; @@ -37,7 +41,6 @@ private void InitDefaultValues() _maxSendMessageSize = GrpcDefaultSettings.MaxSendMessageSize; _maxReceiveMessageSize = GrpcDefaultSettings.MaxReceiveMessageSize; _disableDiscovery = GrpcDefaultSettings.DisableDiscovery; - _createSessionTimeout = SessionPoolDefaultSettings.CreateSessionTimeoutSeconds; _disableServerBalancer = false; } @@ -123,6 +126,58 @@ public int MaxSessionPool private int _maxSessionPool; + public int MinSessionPool + { + get => _minSessionPool; + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, "Invalid min session pool: " + value); + } + + _minSessionPool = value; + SaveValue(nameof(MinSessionPool), value); + } + } + + private int _minSessionPool; + + public int SessionIdleTimeout + { + get => _sessionIdleTimeout; + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, "Invalid session idle timeout: " + value); + } + + _sessionIdleTimeout = value; + SaveValue(nameof(SessionIdleTimeout), value); + } + } + + private int _sessionIdleTimeout; + + public int SessionPruningInterval + { + get => _sessionPruningInterval; + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(value), value, + "Invalid session pruning interval: " + value); + } + + _sessionPruningInterval = value; + SaveValue(nameof(SessionPruningInterval), value); + } + } + + private int _sessionPruningInterval; + public bool UseTls { get => _useTls; @@ -416,9 +471,12 @@ static YdbConnectionOption() (builder, user) => builder.User = user), "User", "Username", "UserId", "User Id"); AddOption(new YdbConnectionOption(StringExtractor, (builder, password) => builder.Password = password), "Password", "PWD", "PSW"); - AddOption(new YdbConnectionOption(IntExtractor, - (builder, maxSessionPool) => builder.MaxSessionPool = maxSessionPool), - "MaxSessionPool", "Max Session Pool", "Maximum Pool Size", "Max Pool Size", "MaximumPoolSize"); + AddOption(new YdbConnectionOption(IntExtractor, (builder, maxSessionPool) => + builder.MaxSessionPool = maxSessionPool), "MaxSessionPool", "Max Session Pool", "Maximum Pool Size", + "MaximumPoolSize", "Max Pool Size", "MaxPoolSize"); + AddOption(new YdbConnectionOption(IntExtractor, (builder, minSessionSize) => + builder.MinSessionPool = minSessionSize), "MinSessionPool", "Min Session Pool", "Minimum Pool Size", + "MinimumPoolSize", "Min Pool Size", "MinPoolSize"); AddOption(new YdbConnectionOption(BoolExtractor, (builder, useTls) => builder.UseTls = useTls), "UseTls", "Use Tls"); AddOption(new YdbConnectionOption(StringExtractor, @@ -446,8 +504,14 @@ static YdbConnectionOption() AddOption(new YdbConnectionOption(IntExtractor, (builder, createSessionTimeout) => builder.CreateSessionTimeout = createSessionTimeout), "CreateSessionTimeout", "Create Session Timeout"); - AddOption(new YdbConnectionOption(BoolExtractor, (builder, disableServerBalancer) => - builder.DisableServerBalancer = disableServerBalancer), + AddOption(new YdbConnectionOption(IntExtractor, + (builder, sessionIdleTimeout) => builder.SessionIdleTimeout = sessionIdleTimeout), + "SessionIdleTimeout", "Session Idle Timeout"); + AddOption(new YdbConnectionOption(IntExtractor, + (builder, sessionPruningInterval) => builder.SessionPruningInterval = sessionPruningInterval), + "SessionPruningInterval", "Session Pruning Interval"); + AddOption(new YdbConnectionOption(BoolExtractor, + (builder, disableServerBalancer) => builder.DisableServerBalancer = disableServerBalancer), "DisableServerBalancer", "Disable Server Balancer"); } diff --git a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs index c892c896..967e0f28 100644 --- a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs +++ b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs @@ -12,7 +12,11 @@ public void InitDefaultValues_WhenEmptyConstructorInvoke_ReturnDefaultConnection Assert.Equal(2136, ydbConnectionStringBuilder.Port); Assert.Equal("localhost", ydbConnectionStringBuilder.Host); Assert.Equal("/local", ydbConnectionStringBuilder.Database); + Assert.Equal(0, ydbConnectionStringBuilder.MinSessionPool); Assert.Equal(100, ydbConnectionStringBuilder.MaxSessionPool); + Assert.Equal(5, ydbConnectionStringBuilder.CreateSessionTimeout); + Assert.Equal(300, ydbConnectionStringBuilder.SessionIdleTimeout); + Assert.Equal(10, ydbConnectionStringBuilder.SessionPruningInterval); Assert.Null(ydbConnectionStringBuilder.User); Assert.Null(ydbConnectionStringBuilder.Password); Assert.Equal(5, ydbConnectionStringBuilder.ConnectTimeout); @@ -24,7 +28,6 @@ public void InitDefaultValues_WhenEmptyConstructorInvoke_ReturnDefaultConnection Assert.Equal(64 * 1024 * 1024, ydbConnectionStringBuilder.MaxReceiveMessageSize); Assert.False(ydbConnectionStringBuilder.DisableDiscovery); Assert.False(ydbConnectionStringBuilder.DisableServerBalancer); - Assert.Equal(5, ydbConnectionStringBuilder.CreateSessionTimeout); Assert.False(ydbConnectionStringBuilder.UseTls); } @@ -43,17 +46,22 @@ public void InitConnectionStringBuilder_WhenExpectedKeys_ReturnUpdatedConnection { var connectionString = new YdbConnectionStringBuilder( "Host=server;Port=2135;Database=/my/path;User=Kirill;UseTls=true;" + + "MinSessionPool=10;MaxSessionPool=50;CreateSessionTimeout=30;" + + "SessionIdleTimeout=600;SessionPruningInterval=20;" + "ConnectTimeout=30;KeepAlivePingDelay=30;KeepAlivePingTimeout=60;" + - "EnableMultipleHttp2Connections=true;CreateSessionTimeout=30;" + + "EnableMultipleHttp2Connections=true;" + "MaxSendMessageSize=1000000;MaxReceiveMessageSize=1000000;" + - "DisableDiscovery=true;DisableServerBalancer=true;" + - "MaxSessionPool=50" + "DisableDiscovery=true;DisableServerBalancer=true;" ); Assert.Equal(2135, connectionString.Port); Assert.Equal("server", connectionString.Host); Assert.Equal("/my/path", connectionString.Database); + Assert.Equal(10, connectionString.MinSessionPool); Assert.Equal(50, connectionString.MaxSessionPool); + Assert.Equal(30, connectionString.CreateSessionTimeout); + Assert.Equal(600, connectionString.SessionIdleTimeout); + Assert.Equal(20, connectionString.SessionPruningInterval); Assert.Equal("Kirill", connectionString.User); Assert.Equal(30, connectionString.ConnectTimeout); Assert.Equal(30, connectionString.KeepAlivePingDelay); @@ -64,14 +72,14 @@ public void InitConnectionStringBuilder_WhenExpectedKeys_ReturnUpdatedConnection Assert.Equal(1000000, connectionString.MaxReceiveMessageSize); Assert.Equal("Host=server;Port=2135;Database=/my/path;User=Kirill;UseTls=True;" + "ConnectTimeout=30;KeepAlivePingDelay=30;KeepAlivePingTimeout=60;" + - "EnableMultipleHttp2Connections=True;CreateSessionTimeout=30;" + + "MinSessionPool=10;MaxSessionPool=50;CreateSessionTimeout=30;" + + "SessionIdleTimeout=600;SessionPruningInterval=20;" + + "EnableMultipleHttp2Connections=True;" + "MaxSendMessageSize=1000000;MaxReceiveMessageSize=1000000;" + "DisableDiscovery=True;DisableServerBalancer=True;" + "MaxSessionPool=50", connectionString.ConnectionString); Assert.True(connectionString.DisableDiscovery); Assert.True(connectionString.DisableServerBalancer); - Assert.Equal(30, connectionString.CreateSessionTimeout); - Assert.Equal(50, connectionString.MaxSessionPool); } [Fact] From 125e980a97f6c0b9153f94f1c4c9b474482e2fca Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Wed, 16 Jul 2025 18:42:39 +0300 Subject: [PATCH 2/4] fix --- src/Ydb.Sdk/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ydb.Sdk/CHANGELOG.md b/src/Ydb.Sdk/CHANGELOG.md index 86cad751..93dde306 100644 --- a/src/Ydb.Sdk/CHANGELOG.md +++ b/src/Ydb.Sdk/CHANGELOG.md @@ -1,6 +1,6 @@ - Added new ADO.NET options: - `MinSessionPool`: The minimum connection pool size. - - `SessionIdleTimeout`: The time (in seconds) to wait before closing idle session in the pool if the count of all connections exceeds `MinSessionPool`. + - `SessionIdleTimeout`: The time (in seconds) to wait before closing idle session in the pool if the count of all sessions exceeds `MinSessionPool`. - `SessionPruningInterval`: How many seconds the pool waits before attempting to prune idle sessions (see `SessionIdleTimeout`). - Fixed bug `Reader`: unhandled exception in `TryReadRequestBytes(long bytes)`. - Handle `YdbException` on `DeleteSession`. From 4cc02e2bea5176b846f63962700ed24d40e373d1 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Wed, 16 Jul 2025 18:46:18 +0300 Subject: [PATCH 3/4] fix --- .../Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs index 967e0f28..62372c4d 100644 --- a/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs +++ b/src/Ydb.Sdk/test/Ydb.Sdk.Ado.Tests/YdbConnectionStringBuilderTests.cs @@ -71,13 +71,12 @@ public void InitConnectionStringBuilder_WhenExpectedKeys_ReturnUpdatedConnection Assert.Equal(1000000, connectionString.MaxSendMessageSize); Assert.Equal(1000000, connectionString.MaxReceiveMessageSize); Assert.Equal("Host=server;Port=2135;Database=/my/path;User=Kirill;UseTls=True;" + - "ConnectTimeout=30;KeepAlivePingDelay=30;KeepAlivePingTimeout=60;" + "MinSessionPool=10;MaxSessionPool=50;CreateSessionTimeout=30;" + "SessionIdleTimeout=600;SessionPruningInterval=20;" + + "ConnectTimeout=30;KeepAlivePingDelay=30;KeepAlivePingTimeout=60;" + "EnableMultipleHttp2Connections=True;" + "MaxSendMessageSize=1000000;MaxReceiveMessageSize=1000000;" + - "DisableDiscovery=True;DisableServerBalancer=True;" + - "MaxSessionPool=50", connectionString.ConnectionString); + "DisableDiscovery=True;DisableServerBalancer=True", connectionString.ConnectionString); Assert.True(connectionString.DisableDiscovery); Assert.True(connectionString.DisableServerBalancer); } From 9b7870a88c4a3658d42324e97ba2e1ab5296aa25 Mon Sep 17 00:00:00 2001 From: KirillKurdyukov Date: Wed, 16 Jul 2025 19:19:57 +0300 Subject: [PATCH 4/4] fix flap test --- src/Ydb.Sdk/test/Ydb.Sdk.Topic.Tests/ReaderUnitTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ydb.Sdk/test/Ydb.Sdk.Topic.Tests/ReaderUnitTests.cs b/src/Ydb.Sdk/test/Ydb.Sdk.Topic.Tests/ReaderUnitTests.cs index 4052e84c..8d5795f9 100644 --- a/src/Ydb.Sdk/test/Ydb.Sdk.Topic.Tests/ReaderUnitTests.cs +++ b/src/Ydb.Sdk/test/Ydb.Sdk.Topic.Tests/ReaderUnitTests.cs @@ -1093,7 +1093,7 @@ public async Task _mockStream.Verify(stream => stream.Write(It.Is(msg => msg.InitRequest != null && msg.InitRequest.Consumer == "Consumer" && - msg.InitRequest.TopicsReadSettings[0].Path == "/topic")), Times.Between(2, 3, Range.Inclusive)); + msg.InitRequest.TopicsReadSettings[0].Path == "/topic")), Times.AtLeast(2)); _mockStream.Verify(stream => stream.Write(It.Is(msg => msg.ReadRequest != null && msg.ReadRequest.BytesSize == 100)), Times.Exactly(2)); _mockStream.Verify(stream => stream.Write(It.Is(msg =>