Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 48719a0

Browse files
committed
Avoid creating cleaning timer if no connections will ever be added to pool
1 parent f8933eb commit 48719a0

File tree

1 file changed

+40
-32
lines changed

1 file changed

+40
-32
lines changed

src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Collections.Concurrent;
66
using System.Collections.Generic;
77
using System.Diagnostics;
8-
using System.Net.Http.Headers;
98
using System.Threading;
109
using 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

Comments
 (0)