diff --git a/src/Grpc.Net.Client/GrpcChannel.cs b/src/Grpc.Net.Client/GrpcChannel.cs index 84ed7d457..3b53c7a4d 100644 --- a/src/Grpc.Net.Client/GrpcChannel.cs +++ b/src/Grpc.Net.Client/GrpcChannel.cs @@ -267,7 +267,7 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad type = HttpHandlerType.SocketsHttpHandler; connectTimeout = socketsHttpHandler.ConnectTimeout; - connectionIdleTimeout = socketsHttpHandler.PooledConnectionIdleTimeout; + connectionIdleTimeout = GetConnectionIdleTimeout(socketsHttpHandler); // Check if the SocketsHttpHandler is being shared by channels. // It has already been setup by another channel (i.e. ConnectCallback is set) then @@ -312,6 +312,27 @@ private static HttpHandlerContext CalculateHandlerContext(ILogger logger, Uri ad } return new HttpHandlerContext(HttpHandlerType.Custom); + +#if NET5_0_OR_GREATER + static TimeSpan? GetConnectionIdleTimeout(SocketsHttpHandler socketsHttpHandler) + { + // Check if either TimeSpan is InfiniteTimeSpan, and return the other one. + if (socketsHttpHandler.PooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan) + { + return socketsHttpHandler.PooledConnectionLifetime; + } + + if (socketsHttpHandler.PooledConnectionLifetime == Timeout.InfiniteTimeSpan) + { + return socketsHttpHandler.PooledConnectionIdleTimeout; + } + + // Return the bigger TimeSpan. + return socketsHttpHandler.PooledConnectionIdleTimeout > socketsHttpHandler.PooledConnectionLifetime + ? socketsHttpHandler.PooledConnectionIdleTimeout + : socketsHttpHandler.PooledConnectionLifetime; + } +#endif } #if NET5_0_OR_GREATER diff --git a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs index ff20ab60d..f3b86b341 100644 --- a/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs +++ b/test/Grpc.Net.Client.Tests/GrpcChannelTests.cs @@ -222,17 +222,35 @@ public void Build_ConnectTimeout_ReadFromSocketsHttpHandler() Assert.AreEqual(TimeSpan.FromSeconds(1), channel.ConnectTimeout); } - [Test] - public void Build_ConnectionIdleTimeout_ReadFromSocketsHttpHandler() + [TestCase(-1, -1, -1)] + [TestCase(0, 0, 0)] + [TestCase(0, -1, 0)] + [TestCase(-1, 0, 0)] + [TestCase(1000, -1, 1000)] + [TestCase(-1, 1000, 1000)] + [TestCase(500, 1000, 1000)] + [TestCase(1000, 500, 1000)] + public void Build_ConnectionIdleTimeout_ReadFromSocketsHttpHandler( + int? pooledConnectionIdleTimeoutMs, + int? pooledConnectionLifetimeMs, + int expectedConnectionIdleTimeoutMs) { - // Arrange & Act - var channel = GrpcChannel.ForAddress("https://localhost", CreateGrpcChannelOptions(o => o.HttpHandler = new SocketsHttpHandler + // Arrange + var handler = new SocketsHttpHandler(); + if (pooledConnectionIdleTimeoutMs != null) { - PooledConnectionIdleTimeout = TimeSpan.FromSeconds(1) - })); + handler.PooledConnectionIdleTimeout = TimeSpan.FromMilliseconds(pooledConnectionIdleTimeoutMs.Value); + } + if (pooledConnectionLifetimeMs != null) + { + handler.PooledConnectionLifetime = TimeSpan.FromMilliseconds(pooledConnectionLifetimeMs.Value); + } + + // Act + var channel = GrpcChannel.ForAddress("https://localhost", CreateGrpcChannelOptions(o => o.HttpHandler = handler)); // Assert - Assert.AreEqual(TimeSpan.FromSeconds(1), channel.ConnectionIdleTimeout); + Assert.AreEqual(TimeSpan.FromMilliseconds(expectedConnectionIdleTimeoutMs), channel.ConnectionIdleTimeout); } #endif