Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly set connection lease timeout regardless of .NET target framework #3279

Merged
merged 3 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
11 changes: 3 additions & 8 deletions iothub/device/src/Transport/Http/HttpClientHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,6 @@ public HttpClientHelper(
_authenticationHeaderProvider = authenticationHeaderProvider;
_defaultErrorMapping = new ReadOnlyDictionary<HttpStatusCode, Func<HttpResponseMessage, Task<Exception>>>(defaultErrorMapping);

ServicePoint servicePoint = ServicePointManager.FindServicePoint(_baseAddress);
servicePoint.ConnectionLeaseTimeout = s_defaultConnectionLeaseTimeout.Milliseconds;

#if NET451
TlsVersions.Instance.SetLegacyAcceptableVersions();

Expand All @@ -104,8 +101,6 @@ public HttpClientHelper(
_httpClientHandler.UseProxy = (proxy != null);
_httpClientHandler.Proxy = proxy;
}

_httpClientObj = _httpClientHandler != null ? new HttpClient(_httpClientHandler) : new HttpClient();
#else

_httpClientHandler = httpClientHandler ?? new HttpClientHandler();
Expand All @@ -123,11 +118,11 @@ public HttpClientHelper(
_httpClientHandler.UseProxy = proxy != null;
_httpClientHandler.Proxy = proxy;
}
#endif

_httpClientHandler.MaxConnectionsPerServer = DefaultMaxConnectionsPerServer;
ServicePointHelpers.SetLimits(_httpClientHandler, _baseAddress);

_httpClientObj = new HttpClient(_httpClientHandler);
#endif
_httpClientObj = _httpClientHandler != null ? new HttpClient(_httpClientHandler) : new HttpClient();
timtay-microsoft marked this conversation as resolved.
Show resolved Hide resolved

_httpClientObj.BaseAddress = _baseAddress;
_httpClientObj.Timeout = timeout;
Expand Down
48 changes: 48 additions & 0 deletions iothub/device/src/Transport/Http/ServicePointHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Net;
using System.Net.Http;

namespace Microsoft.Azure.Devices.Client
{
// This type manages changing HttpClient defaults to more appropriate values
// There are two limits we target:
// - Per Server Connection Limit
// - Keep Alive Connection Timeout
// On .NET Core 2.1+ the HttpClient defaults to using the HttpSocketHandler so we adjust both limits on the client handler
//
// On .NET Standard & NET 4.51+ the HttpClient defaults to using the HttpClientHandler
// and there is no easy way to set Keep Alive Connection Timeout but it's mitigated by setting the service point's connection lease timeout
internal static class ServicePointHelpers
timtay-microsoft marked this conversation as resolved.
Show resolved Hide resolved
{
// These default values are consistent with Azure.Core default values:
// https://github.com/Azure/azure-sdk-for-net/blob/7e3cf643977591e9041f4c628fd4d28237398e0b/sdk/core/Azure.Core/src/Pipeline/ServicePointHelpers.cs#L28
internal const int DefaultMaxConnectionsPerServer = 50;

internal const int DefaultConnectionLeaseTimeout = 300 * 1000; // 5 minutes

// messageHandler passed in is an HttpClientHandler for .NET Framework and .NET standard, and a SocketsHttpHandler for .NET core
public static void SetLimits(HttpMessageHandler messageHandler, Uri baseUri, int connectionLeaseTimeoutMilliseconds = DefaultConnectionLeaseTimeout)
{
switch (messageHandler)
{
case HttpClientHandler httpClientHandler:
#if !NET451
httpClientHandler.MaxConnectionsPerServer = DefaultMaxConnectionsPerServer;
#endif
ServicePoint servicePoint = ServicePointManager.FindServicePoint(baseUri);
servicePoint.ConnectionLeaseTimeout = connectionLeaseTimeoutMilliseconds;
break;
#if NETCOREAPP2_1_OR_GREATER || NET5_0_OR_GREATER
// SocketsHttpHandler is only available in netcore2.1 and onwards
case SocketsHttpHandler socketsHttpHandler:
socketsHttpHandler.MaxConnectionsPerServer = DefaultMaxConnectionsPerServer;
socketsHttpHandler.PooledConnectionLifetime = TimeSpan.FromMilliseconds(connectionLeaseTimeoutMilliseconds);
break;
#endif
}
}
}
}