-
Notifications
You must be signed in to change notification settings - Fork 927
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support adding gRPC interceptors using annotation '@GrpcInterceptor' #5397
base: main
Are you sure you want to change the base?
Support adding gRPC interceptors using annotation '@GrpcInterceptor' #5397
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry about the late review. Left some suggestions. 😄
public @interface GrpcInterceptor { | ||
|
||
/** | ||
* {@link GrpcExceptionHandlerFunction} implementation type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* {@link GrpcExceptionHandlerFunction} implementation type. | |
* {@link ServerInterceptor} implementation type. |
grpc/src/main/java/com/linecorp/armeria/server/grpc/GrpcServiceBuilder.java
Show resolved
Hide resolved
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5397 +/- ##
============================================
- Coverage 74.05% 74.01% -0.04%
+ Complexity 21253 20745 -508
============================================
Files 1850 1800 -50
Lines 78600 76488 -2112
Branches 10032 9737 -295
============================================
- Hits 58209 56615 -1594
+ Misses 15686 15263 -423
+ Partials 4705 4610 -95 ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this PR looks good. Is there anything left for discussion or feedback, @Dogacel ?
final DependencyInjector dependencyInjector = new ReflectiveDependencyInjector(); | ||
|
||
// Intercept entries using {@link GrpcInterceptor} annotations and globally added interceptors. | ||
interceptEntries(dependencyInjector); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not your work but there was a bug before. We should not create a DependencyInjector
internally but use ServerConfig.dependencyInjector()
instead.
Let me add a commit for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was difficult to inject ServerConfig.dependencyInjector()
without a huge refactoring. It would be better to use ReflectiveDependencyInjector
as is in this PR. I will send a f/u PR to fix it when this PR is merged.
Could you add a TODO
comment so as not to forget it?
// TODO(ikhoon): Use ServerConfig.dependencyInjector() instead of creating ReflectiveDependencyInjector directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, I will review the implementation correctness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed a commit to fix checkstyle error. Let me know if there are any other concerns 🙂
13d7826
to
1ffe89d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! I think we should do a follow-up so this uses the configured dependency injector.
private static class AnnotatedInterceptorServiceImpl extends TestServiceImplBase { | ||
|
||
@Override | ||
@GrpcInterceptor(InterceptorAddQux.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the order should be:
- global decorator -> class level decorator -> method level decorator
like how@Decorator
works.
However, the current order is reversed. Could you fix it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, let me fix 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm taking a look at the test,
assertThat(headersCapture.get().get(TEST_HEADER)).isEqualTo("foobarqux");
Here first Foo
(global) is appended, later bar
which is the class level and finally qux
which is the method level. Am I reading this incorrectly? I feel like this is the right order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we append headers in requests, not responses so the order of foo bar qux
indicate order of decorators being executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like addToHeader
is called in the reverse order.
You can check the order by simply adding a log:
private static class InterceptorAddFoo implements ServerInterceptor {
@Override
public <REQ, RESP> Listener<REQ> interceptCall(ServerCall<REQ, RESP> call, Metadata headers,
ServerCallHandler<REQ, RESP> next) {
System.err.println("Should call first");
return next.startCall(addToHeader("foo", call), headers);
}
}
private static class InterceptorAddBar implements ServerInterceptor {
@Override
public <REQ, RESP> Listener<REQ> interceptCall(ServerCall<REQ, RESP> call, Metadata headers,
ServerCallHandler<REQ, RESP> next) {
System.err.println("Should call second");
return next.startCall(addToHeader("bar", call), headers);
}
}
private static class InterceptorAddQux implements ServerInterceptor {
@Override
public <REQ, RESP> Listener<REQ> interceptCall(ServerCall<REQ, RESP> call, Metadata headers,
ServerCallHandler<REQ, RESP> next) {
System.err.println("Should call third");
return next.startCall(addToHeader("qux", call), headers);
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed 🙌
Bump ^ 🙂 Seems like this was forgotten |
Motivation:
#5359
Adding annotations to add interceptors to gRPC services and methods.
Modifications:
GrpcInterceptor
annotation.GrpcServerBuilder
to find interceptors defined by annotations on gRPC servers and methods.Result:
@GrpcInterceptor
#5359The way services are added to the
HandlerRegistry
has changed slightly, now we are not adding the wholeService
objects as an entry but rather we find allMethodDescriptors
under those services and add those methods one by one asEntry
objects. The reason is that we can't create a single interceptor under a singleService
object that would intercept individual methods, those methods need to be added as separate entries.It can be checked if there is any method interception annotations and if there isn't any, it can fallback to the legacy logic (add the whole
Service
object as anEntry
).Question Do you think adding each method as a separate
Entry
would create performance issues?Also, let me know if the interceptor order looks right based on the test.