Ejemplo n.º 1
0
        public async Task DisconnectEndpoint_NoCallsMade_SubchannelStateUpdated()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint.Address });

            await channel.ConnectAsync().DefaultTimeout();

            var subchannel = await BalancerHelpers.WaitForSubchannelToBeReadyAsync(Logger, channel).DefaultTimeout();

            // Act
            endpoint.Dispose();

            // Assert
            await TestHelpers.AssertIsTrueRetryAsync(
                () => subchannel.State == ConnectivityState.TransientFailure,
                "Wait for subchannel to fail.").DefaultTimeout();
        }
Ejemplo n.º 2
0
        public async Task Resolver_SubchannelTransientFailure_ResolverRefreshed()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            SyncPoint?syncPoint = new SyncPoint(runContinuationsAsynchronously: true);

            syncPoint.Continue();

            var resolver = new TestResolver(async() =>
            {
                await syncPoint.WaitToContinue().DefaultTimeout();
                syncPoint = new SyncPoint(runContinuationsAsynchronously: true);
            });

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port),
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            });

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), resolver, connect : true);

            await BalancerHelpers.WaitForSubChannelsToBeReadyAsync(Logger, channel, 2).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            var waitForRefreshTask = syncPoint.WaitForSyncPoint();

            endpoint1.Dispose();

            await waitForRefreshTask.DefaultTimeout();

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            });

            syncPoint.Continue();

            await BalancerHelpers.WaitForSubChannelsToBeReadyAsync(Logger, channel, 1).DefaultTimeout();
        }
Ejemplo n.º 3
0
        public async Task UnaryCall_MultipleCalls_RoundRobin()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint1.Address, endpoint2.Address }, connect : true);

            await BalancerHelpers.WaitForSubchannelsToBeReadyAsync(Logger, channel, 2).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            var nextHost = GetNextHost(host !);

            // Act
            reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual(nextHost, host !);
            nextHost = GetNextHost(host !);

            // Act
            reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual(nextHost, host);

            string GetNextHost(string host)
            {
                return(host == "127.0.0.1:50051" ? "127.0.0.1:50052" : "127.0.0.1:50051");
            }
        }
Ejemplo n.º 4
0
        public async Task Client_CallCredentials_WithLoadBalancing_RoundtripToken()
        {
            // Arrange
            string?authorization = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                authorization = context.RequestHeaders.GetValue("authorization");
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            var credentials = CallCredentials.FromInterceptor((context, metadata) =>
            {
                metadata.Add("Authorization", $"Bearer TEST");
                return(Task.CompletedTask);
            });

            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true);
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true);

            var services = new ServiceCollection();

            services.AddSingleton <ResolverFactory>(new StaticResolverFactory(_ => new[]
            {
                new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port),
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            }));
            var socketsHttpHandler = new SocketsHttpHandler
            {
                EnableMultipleHttp2Connections = true,
                SslOptions = new System.Net.Security.SslClientAuthenticationOptions
                {
                    EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
                    RemoteCertificateValidationCallback = (_, __, ___, ____) => true
                }
            };
            var channel = GrpcChannel.ForAddress("static:///localhost", new GrpcChannelOptions
            {
                LoggerFactory   = LoggerFactory,
                ServiceProvider = services.BuildServiceProvider(),
                Credentials     = ChannelCredentials.Create(new SslCredentials(), credentials),
                HttpHandler     = socketsHttpHandler
            });

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Bearer TEST", authorization);
            Assert.AreEqual("Balancer", reply.Message);
        }
Ejemplo n.º 5
0
        public async Task UnaryCall_UnavailableAddress_FallbackToWorkingAddress()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint1.Address, endpoint2.Address }, connect : true);

            await BalancerHelpers.WaitForSubchannelsToBeReadyAsync(Logger, channel, 2).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            var reply1 = await client.UnaryCall(new HelloRequest { Name = "Balancer1" });

            Assert.AreEqual("Balancer1", reply1.Message);
            var host1 = host;

            var reply2 = await client.UnaryCall(new HelloRequest { Name = "Balancer2" });

            Assert.AreEqual("Balancer2", reply2.Message);
            var host2 = host;

            Assert.Contains("127.0.0.1:50051", new[] { host1, host2 });
            Assert.Contains("127.0.0.1:50052", new[] { host1, host2 });

            endpoint1.Dispose();

            var subChannel = await BalancerHelpers.WaitForSubchannelToBeReadyAsync(Logger, channel).DefaultTimeout();

            Assert.AreEqual(50052, subChannel.CurrentAddress?.EndPoint.Port);

            reply1 = await client.UnaryCall(new HelloRequest { Name = "Balancer" });

            Assert.AreEqual("Balancer", reply1.Message);
            Assert.AreEqual("127.0.0.1:50052", host);
        }
Ejemplo n.º 6
0
        public async Task UnaryCall_CallAfterCancellation_Success()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new PickFirstConfig(), new[] { endpoint.Address }).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint.Method);

            // Kill endpoint so client can't connect.
            endpoint.Dispose();

            var cts = new CancellationTokenSource(TimeSpan.FromSeconds(0.5));

            cts.Token.Register(() => Logger.LogInformation("Cancellation token raised"));

            // Start call that is canceled while getting picker.
            await ExceptionAssert.ThrowsAsync <RpcException>(() => client.UnaryCall(
                                                                 new HelloRequest {
                Name = "Balancer"
            },
                                                                 new CallOptions(cancellationToken: cts.Token)).ResponseAsync).DefaultTimeout();

            // Restart endpoint.
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }, new CallOptions().WithWaitForReady(true)).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);
        }
Ejemplo n.º 7
0
        public async Task UnaryCall_ReconnectBetweenCalls_Success()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint.Address });

            var client = TestClientFactory.Create(channel, endpoint.Method);

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);

            Logger.LogInformation("Ending " + endpoint.Address);
            endpoint.Dispose();

            Logger.LogInformation("Restarting");
            using var endpointNew = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            // Act
            reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }, new CallOptions().WithWaitForReady()).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);
        }
Ejemplo n.º 8
0
        public async Task Active_UnaryCall_ConnectTimeout_ErrorThrownWhenTimeoutExceeded()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            var    tcs  = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);
            string?host = null;

            async Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                var protocol = context.GetHttpContext().Request.Protocol;

                Logger.LogInformation("Received protocol: " + protocol);

                await tcs.Task;

                host = context.Host;
                return(new HelloReply {
                    Message = request.Name
                });
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var handler = new SocketsHttpHandler()
            {
                // ConnectTimeout is so small that CT will always be canceled before Socket is used.
                ConnectTimeout = TimeSpan.FromTicks(1),
            };
            var channel = GrpcChannel.ForAddress(endpoint.Address, new GrpcChannelOptions()
            {
                HttpHandler   = handler,
                LoggerFactory = LoggerFactory
            });

            var client = TestClientFactory.Create(channel, endpoint.Method);

            var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => client.UnaryCall(new HelloRequest()).ResponseAsync).DefaultTimeout();

            Assert.AreEqual("A connection could not be established within the configured ConnectTimeout.", ex.Status.DebugException !.Message);
        }
Ejemplo n.º 9
0
        public async Task UnaryCall_SingleAddressFailure_RpcError()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new PickFirstConfig(), new[] { endpoint.Address }).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint.Method);

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);

            Logger.LogInformation("Ending " + endpoint.Address);
            endpoint.Dispose();

            var ex = await ExceptionAssert.ThrowsAsync <RpcException>(
                () => client.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }).ResponseAsync).DefaultTimeout();

            Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode);

            // Sometimes SocketException is wrapped by HttpRequestException.
            Assert.IsTrue(HasExceptionInStack <SocketException>(ex.Status.DebugException), $"Unexpected exception: {ex.Status.DebugException}");
Ejemplo n.º 10
0
        public async Task Subchannel_ResolveRemovesSubchannel_SubchannelCleanedUp()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            var resolver = new TestResolver(LoggerFactory);

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port)
            });

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), resolver, connect : true);

            var disposedSubchannel = await BalancerHelpers.WaitForSubchannelToBeReadyAsync(Logger, channel).DefaultTimeout();

            Assert.IsNotNull(((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport)._initialSocket);

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            });

            Assert.IsNull(((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport)._initialSocket);
        }
Ejemplo n.º 11
0
        public async Task UnaryCall_MultipleCalls_RoundRobin()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            SyncPoint?syncPoint = null;
            string?   host      = null;

            async Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                if (syncPoint != null)
                {
                    await syncPoint.WaitToContinue();
                }

                return(new HelloReply {
                    Message = request.Name
                });
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new LoadBalancingConfig("least_used"), new[] { endpoint1.Address, endpoint2.Address }, connect : true);

            await BalancerHelpers.WaitForSubchannelsToBeReadyAsync(
                Logger,
                channel,
                expectedCount : 2,
                getPickerSubchannels : picker => ((LeastUsedPicker?)picker)?._subchannels.ToArray() ?? Array.Empty <Subchannel>()).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            // Act
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);

            // Act
            reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50051", host);

            // Act
            var sp1          = syncPoint = new SyncPoint(runContinuationsAsynchronously: true);
            var pendingCall1 = client.UnaryCall(new HelloRequest {
                Name = "Balancer"
            });
            // Assert
            await syncPoint.WaitForSyncPoint().DefaultTimeout();

            Assert.AreEqual("127.0.0.1:50051", host);

            // Act
            var sp2          = syncPoint = new SyncPoint(runContinuationsAsynchronously: true);
            var pendingCall2 = client.UnaryCall(new HelloRequest {
                Name = "Balancer"
            });
            // Assert
            await syncPoint.WaitForSyncPoint().DefaultTimeout();

            Assert.AreEqual("127.0.0.1:50052", host);

            // Act
            var sp3          = syncPoint = new SyncPoint(runContinuationsAsynchronously: true);
            var pendingCall3 = client.UnaryCall(new HelloRequest {
                Name = "Balancer"
            });
            // Assert
            await syncPoint.WaitForSyncPoint().DefaultTimeout();

            Assert.AreEqual("127.0.0.1:50051", host);

            sp1.Continue();
            sp2.Continue();
            sp3.Continue();
        }
Ejemplo n.º 12
0
        public async Task Subchannel_ResolveRemovesSubchannelAfterRequest_SubchannelCleanedUp()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod));

            var resolver = new TestResolver(LoggerFactory);

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port)
            });

            var channel = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), resolver, connect : true);

            var disposedSubchannel = await BalancerHelpers.WaitForSubchannelToBeReadyAsync(Logger, channel).DefaultTimeout();

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            var reply1 = await client.UnaryCall(new HelloRequest { Name = "Balancer1" });

            Assert.AreEqual("Balancer1", reply1.Message);
            Assert.AreEqual("127.0.0.1:50051", host !);

            resolver.UpdateAddresses(new List <BalancerAddress>
            {
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            });

            var activeStreams = ((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport).GetActiveStreams();

            Assert.AreEqual(1, activeStreams.Count);
            Assert.AreEqual("127.0.0.1", activeStreams[0].Address.EndPoint.Host);
            Assert.AreEqual(50051, activeStreams[0].Address.EndPoint.Port);

            // Wait until connected to new endpoint
            Subchannel?newSubchannel = null;

            while (true)
            {
                newSubchannel = await BalancerHelpers.WaitForSubchannelToBeReadyAsync(Logger, channel).DefaultTimeout();

                if (newSubchannel.CurrentAddress?.EndPoint.Equals(endpoint2.EndPoint) ?? false)
                {
                    break;
                }
            }

            // Subchannel has a socket until a request is made.
            Assert.IsNotNull(((SocketConnectivitySubchannelTransport)newSubchannel.Transport)._initialSocket);

            endpoint1.Dispose();

            var reply2 = await client.UnaryCall(new HelloRequest { Name = "Balancer2" });

            Assert.AreEqual("Balancer2", reply2.Message);
            Assert.AreEqual("127.0.0.1:50052", host !);

            // Disposed subchannel stream removed when endpoint disposed.
            activeStreams = ((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport).GetActiveStreams();
            Assert.AreEqual(0, activeStreams.Count);
            Assert.IsNull(((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport)._initialSocket);

            // New subchannel stream created with request.
            activeStreams = ((SocketConnectivitySubchannelTransport)newSubchannel.Transport).GetActiveStreams();
            Assert.AreEqual(1, activeStreams.Count);
            Assert.AreEqual("127.0.0.1", activeStreams[0].Address.EndPoint.Host);
            Assert.AreEqual(50052, activeStreams[0].Address.EndPoint.Port);
            Assert.IsNull(((SocketConnectivitySubchannelTransport)disposedSubchannel.Transport)._initialSocket);
        }
Ejemplo n.º 13
0
        public async Task UnaryCall_MultipleChannelsShareHandler_ReconnectBetweenCalls_Success()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            string?host = null;

            Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                host = context.Host;
                return(Task.FromResult(new HelloReply {
                    Message = request.Name
                }));
            }

            // Arrange
            using var endpoint = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            var socketsHttpHandler = new SocketsHttpHandler();
            var channel1           = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint.Address }, socketsHttpHandler);

            var channel2 = await BalancerHelpers.CreateChannel(LoggerFactory, new RoundRobinConfig(), new[] { endpoint.Address }, socketsHttpHandler);

            var client1 = TestClientFactory.Create(channel1, endpoint.Method);
            var client2 = TestClientFactory.Create(channel2, endpoint.Method);

            // Act
            var reply1Task = client1.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }).ResponseAsync.DefaultTimeout();
            var reply2Task = client2.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", (await reply1Task).Message);
            Assert.AreEqual("Balancer", (await reply2Task).Message);
            Assert.AreEqual("127.0.0.1:50051", host);

            // Wait for connecting or failure.
            // Connecting is faster to wait for, but the status could change so quickly that wait for state change is not triggered.
            // Use failure as backup status.
            var expectedStates        = new[] { ConnectivityState.Connecting, ConnectivityState.TransientFailure };
            var waitForConnectingTask = Task.WhenAll(
                BalancerHelpers.WaitForChannelStatesAsync(Logger, channel1, expectedStates, channelId: 1),
                BalancerHelpers.WaitForChannelStatesAsync(Logger, channel2, expectedStates, channelId: 2));

            Logger.LogInformation("Ending " + endpoint.Address);
            endpoint.Dispose();

            await waitForConnectingTask.DefaultTimeout();

            Logger.LogInformation("Restarting");
            using var endpointNew = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod));

            // Act
            reply1Task = client1.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }, new CallOptions().WithWaitForReady()).ResponseAsync.DefaultTimeout();
            reply2Task = client2.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }, new CallOptions().WithWaitForReady()).ResponseAsync.DefaultTimeout();

            // Assert
            Assert.AreEqual("Balancer", (await reply1Task).Message);
            Assert.AreEqual("Balancer", (await reply2Task).Message);
            Assert.AreEqual("127.0.0.1:50051", host);
        }
Ejemplo n.º 14
0
        public async Task Active_UnaryCall_MultipleStreams_UnavailableAddress_FallbackToWorkingAddress()
        {
            // Ignore errors
            SetExpectedErrorsFilter(writeContext =>
            {
                return(true);
            });

            var    tcs  = new TaskCompletionSource <object?>(TaskCreationOptions.RunContinuationsAsynchronously);
            string?host = null;

            async Task <HelloReply> UnaryMethod(HelloRequest request, ServerCallContext context)
            {
                var protocol = context.GetHttpContext().Request.Protocol;

                Logger.LogInformation("Received protocol: " + protocol);

                await tcs.Task;

                host = context.Host;
                return(new HelloReply {
                    Message = request.Name
                });
            }

            // Arrange
            using var endpoint1 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50051, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true);
            using var endpoint2 = BalancerHelpers.CreateGrpcEndpoint <HelloRequest, HelloReply>(50052, UnaryMethod, nameof(UnaryMethod), HttpProtocols.Http1AndHttp2, isHttps: true);

            var services = new ServiceCollection();

            services.AddSingleton <ResolverFactory>(new StaticResolverFactory(_ => new[]
            {
                new BalancerAddress(endpoint1.Address.Host, endpoint1.Address.Port),
                new BalancerAddress(endpoint2.Address.Host, endpoint2.Address.Port)
            }));

            var socketsHttpHandler = new SocketsHttpHandler
            {
                EnableMultipleHttp2Connections = true,
                SslOptions = new System.Net.Security.SslClientAuthenticationOptions()
                {
                    RemoteCertificateValidationCallback = (_, __, ___, ____) => true
                }
            };
            var grpcWebHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, new RequestVersionHandler(socketsHttpHandler));
            var channel        = GrpcChannel.ForAddress("static:///localhost", new GrpcChannelOptions
            {
                LoggerFactory   = LoggerFactory,
                HttpHandler     = grpcWebHandler,
                ServiceProvider = services.BuildServiceProvider(),
                Credentials     = new SslCredentials()
            });

            var client = TestClientFactory.Create(channel, endpoint1.Method);

            // Act
            grpcWebHandler.HttpVersion = new Version(1, 1);
            var http11CallTasks = new List <Task <HelloReply> >();

            for (int i = 0; i < 10; i++)
            {
                Logger.LogInformation($"Sending gRPC call {i}");

                http11CallTasks.Add(client.UnaryCall(new HelloRequest {
                    Name = "Balancer"
                }).ResponseAsync);
            }

            Logger.LogInformation($"Done sending gRPC calls");

            var balancer      = BalancerHelpers.GetInnerLoadBalancer <PickFirstBalancer>(channel) !;
            var subchannel    = balancer._subchannel !;
            var transport     = (SocketConnectivitySubchannelTransport)subchannel.Transport;
            var activeStreams = transport.GetActiveStreams();

            // Assert
            Assert.AreEqual(HttpHandlerType.SocketsHttpHandler, channel.HttpHandlerType);

            await TestHelpers.AssertIsTrueRetryAsync(() =>
            {
                activeStreams = transport.GetActiveStreams();
                return(activeStreams.Count == 10);
            }, "Wait for connections to start.");

            foreach (var t in activeStreams)
            {
                Assert.AreEqual(new DnsEndPoint("127.0.0.1", 50051), t.Address.EndPoint);
            }

            // Act
            grpcWebHandler.HttpVersion = new Version(2, 0);
            var http2CallTasks = new List <Task <HelloReply> >();

            for (int i = 0; i < 10; i++)
            {
                Logger.LogInformation($"Sending gRPC call {i}");

                http2CallTasks.Add(client.UnaryCall(new HelloRequest {
                    Name = "Balancer"
                }).ResponseAsync);
            }

            Logger.LogInformation($"Done sending gRPC calls");

            // Assert
            await TestHelpers.AssertIsTrueRetryAsync(() =>
            {
                activeStreams = transport.GetActiveStreams();
                return(activeStreams.Count == 11);
            }, "Wait for connections to start.");

            Assert.AreEqual(new DnsEndPoint("127.0.0.1", 50051), activeStreams.Last().Address.EndPoint);

            tcs.SetResult(null);

            await Task.WhenAll(http11CallTasks).DefaultTimeout();

            await Task.WhenAll(http2CallTasks).DefaultTimeout();

            Assert.AreEqual(ConnectivityState.Ready, channel.State);

            Logger.LogInformation($"Closing {endpoint1}");
            endpoint1.Dispose();

            // There are still be 10 HTTP/1.1 connections because they aren't immediately removed
            // when the server is shutdown and connectivity is lost.
            await TestHelpers.AssertIsTrueRetryAsync(() =>
            {
                activeStreams = transport.GetActiveStreams();
                return(activeStreams.Count == 10);
            }, "Wait for HTTP/2 connection to end.");

            grpcWebHandler.HttpVersion = new Version(1, 1);

            await Task.Delay(1000);

            Logger.LogInformation($"Starting failed call");
            var ex = await ExceptionAssert.ThrowsAsync <RpcException>(() => client.UnaryCall(new HelloRequest {
                Name = "Balancer"
            }).ResponseAsync).DefaultTimeout();

            Assert.AreEqual(StatusCode.Unavailable, ex.StatusCode);

            // Removed by failed call.
            activeStreams = transport.GetActiveStreams();
            Assert.AreEqual(0, activeStreams.Count);
            Assert.AreEqual(ConnectivityState.Idle, channel.State);

            Logger.LogInformation($"Next call goes to fallback address.");
            var reply = await client.UnaryCall(new HelloRequest { Name = "Balancer" }).ResponseAsync.TimeoutAfter(TimeSpan.FromSeconds(20));

            Assert.AreEqual("Balancer", reply.Message);
            Assert.AreEqual("127.0.0.1:50052", host);

            activeStreams = transport.GetActiveStreams();
            Assert.AreEqual(1, activeStreams.Count);
            Assert.AreEqual(new DnsEndPoint("127.0.0.1", 50052), activeStreams[0].Address.EndPoint);
        }