11using System . Collections . Concurrent ;
2+ using System . Diagnostics ;
23using System . Diagnostics . CodeAnalysis ;
34using System . Runtime . CompilerServices ;
5+ using Microsoft . Extensions . Logging ;
46using Ydb . Query ;
57
68namespace Ydb . Sdk . Ado . Session ;
79
810internal sealed class PoolingSessionSource < T > : ISessionSource where T : PoolingSessionBase < T >
911{
12+ private const int DisposeTimeoutSeconds = 10 ;
13+
1014 private readonly ConcurrentStack < T > _idleSessions = new ( ) ;
1115 private readonly ConcurrentQueue < TaskCompletionSource < T ? > > _waiters = new ( ) ;
1216 private readonly CancellationTokenSource _disposeCts = new ( ) ;
@@ -18,16 +22,14 @@ internal sealed class PoolingSessionSource<T> : ISessionSource where T : Pooling
1822 private readonly int _createSessionTimeout ;
1923 private readonly TimeSpan _sessionIdleTimeout ;
2024 private readonly Timer _cleanerTimer ;
25+ private readonly ILogger _logger ;
2126
2227 private volatile int _numSessions ;
2328 private volatile int _disposed ;
2429
2530 private bool IsDisposed => _disposed == 1 ;
2631
27- public PoolingSessionSource (
28- IPoolingSessionFactory < T > sessionFactory ,
29- YdbConnectionStringBuilder settings
30- )
32+ public PoolingSessionSource ( IPoolingSessionFactory < T > sessionFactory , YdbConnectionStringBuilder settings )
3133 {
3234 _sessionFactory = sessionFactory ;
3335 _minSessionSize = settings . MinSessionPool ;
@@ -43,6 +45,7 @@ YdbConnectionStringBuilder settings
4345 _createSessionTimeout = settings . CreateSessionTimeout ;
4446 _sessionIdleTimeout = TimeSpan . FromSeconds ( settings . SessionIdleTimeout ) ;
4547 _cleanerTimer = new Timer ( CleanIdleSessions , this , _sessionIdleTimeout , _sessionIdleTimeout ) ;
48+ _logger = settings . LoggerFactory . CreateLogger < PoolingSessionSource < T > > ( ) ;
4649 }
4750
4851 public ValueTask < ISession > OpenSession ( CancellationToken cancellationToken = default )
@@ -156,7 +159,7 @@ private async ValueTask<ISession> RentAsync(CancellationToken cancellationToken)
156159 try
157160 {
158161 if ( IsDisposed )
159- throw new YdbException ( "The session source has been shut down ." ) ;
162+ throw new YdbException ( "The session source has been shutdown ." ) ;
160163
161164 var session = _sessionFactory . NewSession ( this ) ;
162165 await session . Open ( cancellationToken ) ;
@@ -167,8 +170,7 @@ private async ValueTask<ISession> RentAsync(CancellationToken cancellationToken)
167170 return session ;
168171 }
169172
170- throw new YdbException (
171- $ "Could not find free slot in { _sessions } when opening. Please report a bug.") ;
173+ throw new YdbException ( $ "Could not find free slot in { _sessions } when opening. Please report a bug.") ;
172174 }
173175 catch
174176 {
@@ -266,6 +268,7 @@ public async ValueTask DisposeAsync()
266268 await _cleanerTimer . DisposeAsync ( ) ;
267269 _disposeCts . Cancel ( ) ;
268270
271+ var sw = Stopwatch . StartNew ( ) ;
269272 var spinWait = new SpinWait ( ) ;
270273 do
271274 {
@@ -280,9 +283,28 @@ public async ValueTask DisposeAsync()
280283 }
281284
282285 spinWait . SpinOnce ( ) ;
283- } while ( _numSessions > 0 ) ;
286+ } while ( _numSessions > 0 && sw . Elapsed < TimeSpan . FromSeconds ( DisposeTimeoutSeconds ) ) ;
287+
288+ try
289+ {
290+ await _sessionFactory . DisposeAsync ( ) ;
291+ }
292+ catch ( Exception e )
293+ {
294+ _logger . LogError ( e , "Failed to dispose the transport driver" ) ;
295+ }
284296
285- await _sessionFactory . DisposeAsync ( ) ;
297+ for ( var i = 0 ; i < _maxSessionSize ; i ++ )
298+ {
299+ var session = Volatile . Read ( ref _sessions [ i ] ) ;
300+
301+ if ( session == null || session . CompareAndSet ( PoolingSessionState . Clean , PoolingSessionState . Clean ) )
302+ continue ;
303+ _logger . LogCritical ( "Disposal timed out: Some sessions are still active" ) ;
304+
305+ throw new YdbException ( "Timeout while disposing of the pool: some sessions are still active. " +
306+ "This may indicate a connection leak or suspended operations." ) ;
307+ }
286308 }
287309}
288310
0 commit comments