55using System . Collections . Concurrent ;
66using System . Collections . Generic ;
77using System . Diagnostics ;
8- using System . Net . Http . Headers ;
98using System . Threading ;
109using System . Threading . Tasks ;
1110
@@ -62,17 +61,42 @@ public HttpConnectionPoolManager(HttpConnectionSettings settings)
6261
6362 // Start out with the timer not running, since we have no pools.
6463 // When it does run, run it with a frequency based on the idle timeout.
65- if ( settings . _pooledConnectionIdleTimeout == Timeout . InfiniteTimeSpan )
64+ if ( settings . _pooledConnectionLifetime != TimeSpan . Zero &&
65+ settings . _pooledConnectionIdleTimeout != TimeSpan . Zero )
6666 {
67- const int DefaultScavengeSeconds = 30 ;
68- _cleanPoolTimeout = TimeSpan . FromSeconds ( DefaultScavengeSeconds ) ;
69- }
70- else
71- {
72- const int ScavengesPerIdle = 4 ;
73- const int MinScavengeSeconds = 1 ;
74- TimeSpan timerPeriod = settings . _pooledConnectionIdleTimeout / ScavengesPerIdle ;
75- _cleanPoolTimeout = timerPeriod . TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan . FromSeconds ( MinScavengeSeconds ) ;
67+ if ( settings . _pooledConnectionIdleTimeout == Timeout . InfiniteTimeSpan )
68+ {
69+ const int DefaultScavengeSeconds = 30 ;
70+ _cleanPoolTimeout = TimeSpan . FromSeconds ( DefaultScavengeSeconds ) ;
71+ }
72+ else
73+ {
74+ const int ScavengesPerIdle = 4 ;
75+ const int MinScavengeSeconds = 1 ;
76+ TimeSpan timerPeriod = settings . _pooledConnectionIdleTimeout / ScavengesPerIdle ;
77+ _cleanPoolTimeout = timerPeriod . TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan . FromSeconds ( MinScavengeSeconds ) ;
78+ }
79+
80+ bool restoreFlow = false ;
81+ try
82+ {
83+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
84+ if ( ! ExecutionContext . IsFlowSuppressed ( ) )
85+ {
86+ ExecutionContext . SuppressFlow ( ) ;
87+ restoreFlow = true ;
88+ }
89+
90+ _cleaningTimer = new Timer ( s => ( ( HttpConnectionPoolManager ) s ) . RemoveStalePools ( ) , this , Timeout . Infinite , Timeout . Infinite ) ;
91+ }
92+ finally
93+ {
94+ // Restore the current ExecutionContext
95+ if ( restoreFlow )
96+ {
97+ ExecutionContext . RestoreFlow ( ) ;
98+ }
99+ }
76100 }
77101
78102 // Figure out proxy stuff.
@@ -84,25 +108,6 @@ public HttpConnectionPoolManager(HttpConnectionSettings settings)
84108 _proxyCredentials = _proxy . Credentials ?? settings . _defaultProxyCredentials ;
85109 }
86110 }
87-
88- // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
89- bool restoreFlow = false ;
90- try
91- {
92- if ( ! ExecutionContext . IsFlowSuppressed ( ) )
93- {
94- ExecutionContext . SuppressFlow ( ) ;
95- restoreFlow = true ;
96- }
97-
98- _cleaningTimer = new Timer ( s => ( ( HttpConnectionPoolManager ) s ) . RemoveStalePools ( ) , this , Timeout . Infinite , Timeout . Infinite ) ;
99- }
100- finally
101- {
102- // Restore the current ExecutionContext
103- if ( restoreFlow )
104- ExecutionContext . RestoreFlow ( ) ;
105- }
106111 }
107112
108113 public HttpConnectionSettings Settings => _settings ;
@@ -204,7 +209,7 @@ public Task<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, Uri p
204209 while ( ! _pools . TryGetValue ( key , out pool ) )
205210 {
206211 pool = new HttpConnectionPool ( this , key . Kind , key . Host , key . Port , key . SslHostName , key . ProxyUri , _maxConnectionsPerServer ) ;
207- if ( _pools . TryAdd ( key , pool ) )
212+ if ( _pools . TryAdd ( key , pool ) && _cleaningTimer != null )
208213 {
209214 // We need to ensure the cleanup timer is running if it isn't
210215 // already now that we added a new connection pool.
@@ -263,7 +268,8 @@ public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool doRe
263268 /// <summary>Disposes of the pools, disposing of each individual pool.</summary>
264269 public void Dispose ( )
265270 {
266- _cleaningTimer . Dispose ( ) ;
271+ _cleaningTimer ? . Dispose ( ) ;
272+
267273 foreach ( KeyValuePair < HttpConnectionKey , HttpConnectionPool > pool in _pools )
268274 {
269275 pool . Value . Dispose ( ) ;
@@ -278,6 +284,8 @@ public void Dispose()
278284 /// <summary>Removes unusable connections from each pool, and removes stale pools entirely.</summary>
279285 private void RemoveStalePools ( )
280286 {
287+ Debug . Assert ( _cleaningTimer != null ) ;
288+
281289 // Iterate through each pool in the set of pools. For each, ask it to clear out
282290 // any unusable connections (e.g. those which have expired, those which have been closed, etc.)
283291 // The pool may detect that it's empty and long unused, in which case it'll dispose of itself,
0 commit comments