grpc/grpc-dotnet

How to best pass metadata from one RPC to another

DWIAltonaAnalytics opened this issue · 6 comments

Kind of a follow up question to #1748.

Assume I have an application that is both gRPC server and client.

Some RPC called in the server leads to calling another RPC using the client.

For example if one uses x-correlation-ids to track calls, what is the best practice to pass a metadata-element from one rpc to another?

It would be easiest, if I could access the server call context when I call the client-method.

  • I could pass the context through all my backend-code and all calls made on the way until I reach the client-call
  • I could create a scoped object that holds metadata I am interested in,
  • but the server-call context is part of the http-context and thus exists for the scope and thus I thought it would be best to access the ServerCallContext directly through that instead of creating my own methods.

Now, as the linked question indicates, that should be done by accessing the HttpContext, fine. But the answer there seemed to indicate puzzlement, on why one would want to do that.

Therefore my question is: How to access server call metadata in downstream handling of said call and subsequent calling of other RPCs?

The issue you linked to has an answer.

yes, and as mentioned, the answer is confusing to me, as it implies you do not understand the need to access the context "later on" in the programs flow.

I would like to make sure I don't have an oversight in my architecture, but passing some metadata from one RPC to the next seemed not so strange to me.

If it's useful for you then go ahead. .NET passes OTEL IDs from server to client so you have good company.

For example if one uses x-correlation-ids to track calls, what is the best practice to pass a metadata-element from one rpc to another?

I've seen people use interceptors for correlation propagation.

A server interceptor is used to read the correlation data from the incoming call's metadata from ServerCallContext.RequestHeaders. It is stored in a suitable "ambient" storage location for correlation metadata, like in the current Activity or an AsyncLocal.

Client interceptors know to look at the ambient storage and propagate the correlation metadata on outgoing calls via ClientInterceptorContext.CallOptions.

Using an intermediate storage location means that your in-process logging can be associated with the correlation metadata. It also allows you to propagate correlation metadata across protocols that send metadata differently.

Thanks for both answers!

I was weighing the option of using interceptors and AsyncLocal against using the IServerCallContextFeature of the HttpContext.

for logging I already use logging-scope, which adds the correlation ID to any log message done in that scope.

I think I will go with the AsyncLocal and store the data myself using interceptors.

IHttpContextAccessor uses AsyncLocal for providing the context and is built into ASP.NET Core. It's the first option at #1748 (comment)