grpc/grpc-dotnet

Ability to determine when underlying connection has been made

Closed this issue · 5 comments

Is your feature request related to a problem? Please describe.

I need the ability to determine when a connection is made. Specifically with a bi-directional stream call, but I believe all calls are effected.

This was discussed briefly on twitter.

Describe the solution you'd like

When https://github.com/dotnet/corefx/issues/35404 is complete, it should be possible to expose when the connection is established. I proposed doing so by allowing callers to await an Async variant of the GRPC generated client call. Alternatively, allowing a consumer to subscribe to a Connected or StatusChanged event on the generated Client might be preferable if the former proposal introduces inconsistent behaviour between sync/async calls.

Describe alternatives you've considered

Looking at the HttpClientCallInvoker and it's call through to GrpcCall I was hoping there was an alternative to voiding the RunCall Task, but HttpClient doesn't express when connections are established (yet).

I need the ability to determine when a connection is made. Specifically with a bi-directional stream call, but I believe all calls are effected.

What problem are you solving? It is useful to us to understand why something is needed and how it would be used when evaluate implementing it.

What problem are you solving?

Yeh, I left it abstract as the problem I'm trying to solve is a little involved and I didn't want to muddy the issue too much. I suspect there's much simpler use cases to examine, but, since you ask...

I have an agent that sits deep behind some firewalls, and an api which we'll assume is in the DMZ for brevity's sake. We don't want to punch holes from DMZ to agent (rather any holes be the other way around). So on startup the api uses an intermediary to signal the agent (said intermediary respecting the outward only f/w rules). The agent (client) then establishes a gRPC connection to the api (server), but with an inversed bi-directional stream that looks as follows:

service AgentConnectionService {
	// request & response intentionally inverted
	// "client" connects allowing "server" to make requests
	// (this gets around outbound only firewall constraints)
	rpc Connect(stream Response) returns (stream Request);
}

There is no guarantee that any requests are pending at the point the connection is established / the call is first placed. I can detect when the client connects to the server on the server side because it'll hit the service override, i.e.

public override async Task Connect(IAsyncStreamReader<Response> requestStream, IServerStreamWriter<Request> responseStream, ServerCallContext context)
{
    // if we get here, I know the client has connected
}

I can't however do the same on the client side, because the initial call will void the HttpClient Tasks

var httpClient = new HttpClient(handler);
var options = new GrpcChannelOptions { HttpClient = httpClient };
var channel = GrpcChannel.ForAddress(address, options);
var client = new AgentConnectionService.AgentConnectionServiceClient(channel);
var call = client.Connect();
// am I connected or not? No way of knowing until/unless a message is sent/received

I can attempt to work around this by having the server send a message immediately after a connection is established and/or having a ping/pong. The health of this aspect of the service is determined by the apis ability to ""respond"" (by sending a request in the above signature) to the agent, and I would like to monitor that health on both sides of the connection.

I appreciate there are probably some complexities around how some of the connections work, when they're actually available, etc, which may make this request unfeasible? Definitely appreciate any insights (or pointers to good material to read up on) if that's the case.

I think this basically boils down to #874?

This has been resolved via the API added here in .NET 5: dotnet/runtime#41949

Available now in preview releases together with load balancing

https://docs.microsoft.com/en-us/aspnet/core/grpc/loadbalancing?view=aspnetcore-5.0