4

gRPC requests in .NET rely on channels, that must be shut down and disposed:

using var channel = Grpc.Net.Client.GrpcChannel.ForAddress("path to service");

//...do stuff...

await channel.ShutdownAsync();

I'm wrapping this in a .NET dependency injected service using IServiceCollection, should this be...

  • Per-method - create and dispose the channel inside each method call.
  • AddTransient - a new channel every time my service is requested, but only as long as it's needed.
  • AddScoped - a new channel for each request, but keeping the channel open until the request is done.
  • AddSingleton - a single new channel for the app.

I think AddSingleton is out as I'm not sure how one GrpcChannel will handle lots of parallel requests at the same time and I'd like to pass the CancellationToken for the current request.

Which puts the choice between AddScoped vs AddTransient vs per-method. Without a load of testing (and stumbling into all the pitfalls) I'm not sure what the best practice here is (I'm new to gRPC). Should I be closing the channel as soon as possible, or keeping it open and sharing it between calls?

Keith
  • 150,284
  • 78
  • 298
  • 434

2 Answers2

4

According to Microsoft https://learn.microsoft.com/en-us/aspnet/core/grpc/client?view=aspnetcore-5.0#client-performance :

A channel represents a long-lived connection to a gRPC service.

and

Channel and client performance and usage:

  • Creating a channel can be an expensive operation. Reusing a channel for gRPC calls provides performance benefits.
  • gRPC clients are created with channels. gRPC clients are lightweight objects and don't need to be cached or reused.
  • Multiple gRPC clients can be created from a channel, including different types of clients.
  • A channel and clients created from the channel can safely be used by multiple threads.
  • Clients created from the channel can make multiple simultaneous calls. need to be cached or reused. Multiple gRPC clients can be created from a channel, including different types of clients. A channel and clients created from the channel can safely be used by multiple threads. Clients created from the channel can make multiple simultaneous calls.

According to grpc https://grpc.github.io/grpc/csharp-dotnet/api/Grpc.Net.Client.GrpcChannel.html :

Class GrpcChannel Represents a gRPC channel. Channels are an abstraction of long-lived connections to remote servers. Client objects can reuse the same channel. Creating a channel is an expensive operation compared to invoking a remote call so in general you should reuse a single channel for as many calls as possible.

As always, it depends on what you are trying to do, but probably only single channel should be created by a Singleton. Also, if you really need to handle a heavy load, try using SocketsHttpHandler.EnableMultipleHttp2Connections (https://learn.microsoft.com/en-us/aspnet/core/grpc/performance?view=aspnetcore-5.0#connection-concurrency)

Veglos
  • 458
  • 4
  • 8
0

Grcp clients should be registred with the GrcpClientFactory

builder.Services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
    o.Address = new Uri("https://localhost:5001");
});

(Surprisingly, this registers them as transient)

See: https://learn.microsoft.com/en-us/aspnet/core/grpc/clientfactory?view=aspnetcore-6.0

Lee Smith
  • 6,339
  • 6
  • 27
  • 34