I think existing documentation is appropriate as it is documented from the 
caller of *interceptCall*'s perspective. The order of interceptors being 
invoked follows with the network direction of the call. One interceptor 
instance wraps the call and its corresponding listener. When you do 
*ClientInterceptors.intercept(A, 
B)*, interceptor B is closer to you and interceptor A is closer to the 
network. So the workflow of the call is

   Application -> Interceptor B's decorating code for call -> Interceptor 
A's decorating code for call -> ClientCall (gRPC's code) -> Network

   Network -> ClientCall.Listener (gRPC's code) -> Interceptor A's 
decorating code for call listener -> interceptor B's decorating code for 
call listener -> Application

You feel the server side is the opposite because you are viewing it from 
client application's perspective. If you think about it from server 
application's perspective, it flows in the same way. Another thing that 
could make you feel server interceptor operates oppositely is that server 
calls are started by the remote peer.


When intercepting a call, you should save the state in the interceptor, so 
that both the call and call listener at the same wrapping layer share the 
same view of the state. You can see how we use interceptors for recording 
OpenCensus 
metrics: 
https://github.com/grpc/grpc-java/blob/e73f31a561aa5849dc1d7746f916b79134d0973a/census/src/main/java/io/grpc/census/CensusStatsModule.java#L683-L708

On Tuesday, February 16, 2021 at 6:38:31 AM UTC-8 Philippe Laflamme wrote:

> Hi,
>
> I've noticed a behaviour recently with ClientInterceptor that was a bit 
> surprising and I'm wondering if the documentation needs to be adjusted or 
> whether some other adjustment needs to happen.
>
> The issue is around the ordering of calls when multiple interceptors are 
> present. If one uses ClientInterceptors.intercept(a,b); the 
> documentations states that b will be invoked first.
>
> This is true for calls to the ClientCall methods, but is not for calls to 
> ClientCalls.Listener. The calls to the ClientCall.Listener methods are in 
> the reverse order as the calls to ClientCall methods. So if both a and b 
> above "intercept" the ClientCall.Listener, then the ordering is something 
> like this:
>
> // startCall: b called first
> a.startCall(b.startCall())
>
> // onMessage: a called first
> b.onMessage(a.onMessage())
>
> This makes it impossible for an interceptor to do something like:
>
> * setup some ThreadLocal state
> * invoke the next interceptor's method (e.g.: start or onMessage)
> * teardown ThreadLocal state
>
> This is a common pattern for setting up tracing or logging context or 
> integrating with other frameworks that use ThreadLocal.
>
> I'm assuming this is the expected behaviour, but it is rather surprising 
> when writing a "chain" of interceptors. Especially since the 
> ServerInterceptor don't behave this way. Perhaps the documentation should 
> be adjusted to reflect this more explicitly?
>
> Thanks
>

-- 
You received this message because you are subscribed to the Google Groups 
"grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/grpc-io/71fba76c-7e42-4761-8be7-211a963af1efn%40googlegroups.com.

Reply via email to