[question] using interceptor to populate coroutine context from listener
See original GitHub issueHello!
Was wondering if there is any way to populate coroutine context from the interceptor listeners, i.e. we would like to populate additional MDC elements based on the incoming request and afaik we can only access those from the listener.
class CustomServerInterceptor : ServerInterceptor {
override fun <ReqT : Any, RespT : Any> interceptCall(call: ServerCall<ReqT, RespT>, metadata: Metadata, next: ServerCallHandler<ReqT, RespT>): ServerCall.Listener<ReqT> {
return object: ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(next.startCall(call, metadata)) {
override fun onMessage(message: ReqT) {
// populate MDC here
super.onMessage(message)
}
}
}
}
Above doesn’t work as listeners are invoked after processing all the interceptors. This means that context created by CoroutineContextServerInterceptor.interceptCall()
will use snapshot of values up to that point and even if we modify the MDC in the listeners, those changes will be discarded when performing rpc call on the service (as it will start running a coroutine using the context from the interceptor).
Using workaround of creating custom coroutine context passed to the constructor (https://github.com/grpc/grpc-kotlin/issues/66) also doesn’t work as it appears that bindable service context will be initialized before invoking the listeners as well.
The only other workaround I can think of is to manually populate the MDC from within the RPC methods, e.g.
class HelloWorld : HelloWorldAPIGrpcKt.HelloWorldAPICoroutineImplBase() {
override suspend fun helloWorld(request: HelloWorldRequest): HelloWorldResponse {
MDC.put("foo", "bar")
return withContext(MDCContext()) {
HelloWorldApiProtoBuilders.HelloWorldResponse {
helloWorldString = "Hi ${request.id}"
}
}
}
}
is there any better way?
Issue Analytics
- State:
- Created 3 years ago
- Comments:6
Top GitHub Comments
Yes, I missed that, my bad.
Given that, your described approach is as good as it gets at this time. There’s a related issue, that’s kind of skimmed over in your example code’s comments:
In this block,
message
has a completely unknown type. An interceptor is generally supposed to handle any method: any request type, streaming or unary requests. In the code you gave, you’d have to castmessage
to do anything with it.@lowasser I might be missing something but how would I get access to the request message in custom context interceptor?