-
Notifications
You must be signed in to change notification settings - Fork 918
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
Refactor GrpcStatus to implement GrpcExceptionHandlerFunction #5571
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #5571 +/- ##
============================================
+ Coverage 74.05% 74.10% +0.04%
+ Complexity 21253 21010 -243
============================================
Files 1850 1819 -31
Lines 78600 77399 -1201
Branches 10032 9889 -143
============================================
- Hits 58209 57355 -854
+ Misses 15686 15390 -296
+ Partials 4705 4654 -51 ☔ View full report in Codecov by Sentry. |
4152698
to
866a041
Compare
DefaultGrpcExceptionHandlerFunction.fromThrowable(exceptionHandler, ctx, cause, | ||
metadata) | ||
.withDescription(cause.getMessage()) | ||
.asRuntimeException()); |
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.
Should we set DefaultGrpcExceptionHandlerFunction
as a fallback exception handler for exceptionHandler
when it is set in the GrpcClientBuilder
like we do in ServerBuilder
?
armeria/core/src/main/java/com/linecorp/armeria/server/ServerBuilder.java
Lines 2166 to 2172 in ad3519f
final ServerErrorHandler errorHandler; | |
if (this.errorHandler == null) { | |
errorHandler = ServerErrorHandler.ofDefault(); | |
} else { | |
// Ensure that ServerErrorHandler never returns null by falling back to the default. | |
errorHandler = this.errorHandler.orElse(ServerErrorHandler.ofDefault()); | |
} |
The rest of code should not access to
DefaultGrpcExceptionHandlerFunction
and use the composed one.
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.
Okay, I'll modify to use DefaultGrpcExceptionHandlerFunction
as fallback exception handler.
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.
Global comments) If DefaultGrpcExceptionHandlerFunction
is set as the fallback, should we remove DefaultGrpcExceptionHandlerFunction
here and others?
DefaultGrpcExceptionHandlerFunction.fromThrowable(exceptionHandler, ctx, cause, | |
metadata) | |
.withDescription(cause.getMessage()) | |
.asRuntimeException()); | |
exceptionHandler.apply(ctx, cause, metadata) | |
.withDescription(cause.getMessage()) | |
.asRuntimeException()); |
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.
Ok, I'll
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.
Applied feedback. Thanks
@@ -424,7 +425,7 @@ public void onNext(DeframedMessage message) { | |||
new Metadata()); | |||
} else { | |||
GrpcWebTrailers.set(ctx, trailers); | |||
GrpcStatus.reportStatus(trailers, this); | |||
DefaultGrpcExceptionHandlerFunction.reportStatus(trailers, this); |
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.
reportStatus
is unrelated to GrpcExceptionHandlerFunction
. Should we leave it in GrpcStatus
and only move code handling exceptions to DefaultGrpcExceptionHandlerFunction
?
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.
Thanks for the recommendation. I also think we should separate GrpcStatus
and DefaultGrpcExceptionHandlerFunction
.
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.
Applied feedback. Thanks
…efaultGrpcExceptionHandlerFunction
f838415
to
2613370
Compare
…rpcClient and GrpcServer
2613370
to
0c804ef
Compare
if (exceptionHandler != null) { | ||
option(EXCEPTION_HANDLER.newValue(exceptionHandler)); | ||
if (exceptionHandler == null) { | ||
exceptionHandler = DefaultGrpcExceptionHandlerFunction.ofDefault(); |
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.
Let's expose DefaultGrpcExceptionHandlerFunction
using GrpcExceptionHandlerFunction.ofDefault()
.
exceptionHandler = DefaultGrpcExceptionHandlerFunction.ofDefault(); | |
exceptionHandler = GrpcExceptionHandlerFunction.ofDefault(); |
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.
Ok, I'll.
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.
Applied feedback. Thanks
DefaultGrpcExceptionHandlerFunction.fromThrowable(exceptionHandler, ctx, cause, | ||
metadata) | ||
.withDescription(cause.getMessage()) | ||
.asRuntimeException()); |
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.
Global comments) If DefaultGrpcExceptionHandlerFunction
is set as the fallback, should we remove DefaultGrpcExceptionHandlerFunction
here and others?
DefaultGrpcExceptionHandlerFunction.fromThrowable(exceptionHandler, ctx, cause, | |
metadata) | |
.withDescription(cause.getMessage()) | |
.asRuntimeException()); | |
exceptionHandler.apply(ctx, cause, metadata) | |
.withDescription(cause.getMessage()) | |
.asRuntimeException()); |
grpc/src/main/java/com/linecorp/armeria/internal/client/grpc/ArmeriaClientCall.java
Outdated
Show resolved
Hide resolved
...main/java/com/linecorp/armeria/internal/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
...main/java/com/linecorp/armeria/internal/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
...main/java/com/linecorp/armeria/internal/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
...main/java/com/linecorp/armeria/internal/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
grpc/src/main/java/com/linecorp/armeria/internal/common/grpc/HttpStreamDeframer.java
Outdated
Show resolved
Hide resolved
grpc/src/main/java/com/linecorp/armeria/internal/common/grpc/HttpStreamDeframer.java
Outdated
Show resolved
Hide resolved
@@ -89,19 +89,24 @@ void sortExceptionHandler() { | |||
B1Exception.class); | |||
|
|||
final GrpcExceptionHandlerFunction exceptionHandler = builder.build(); | |||
Status status = GrpcStatus.fromThrowable(exceptionHandler, ctx, new A3Exception(), new Metadata()); | |||
Status status = DefaultGrpcExceptionHandlerFunction.fromThrowable(exceptionHandler, ctx, |
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.
We don't have to use DefaultGrpcExceptionHandlerFunction
to call the exceptionHandler
.
If DefaultGrpcExceptionHandlerFunction
is necessary, exceptionHandler.orElse(GrpcExceptionHandlerFunction.ofDefault()
can be used.
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.
Applied feedback. Thanks
756e8d0
to
5cec1bf
Compare
5cec1bf
to
d38f3be
Compare
grpc/src/main/java/com/linecorp/armeria/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
grpc/src/main/java/com/linecorp/armeria/common/grpc/GrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
|
||
final ClientBuilderParams clientParams = Clients.unwrap(client, ClientBuilderParams.class); | ||
assertThat(clientParams.options().get(GrpcClientOptions.EXCEPTION_HANDLER)) | ||
.isEqualTo(GrpcExceptionHandlerFunction.ofDefault()); |
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.
isSameAs()
is probably a better choice in this case because we want it to be an exactly same instance.
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.
This testcase has been removed after some modification.
But there is still test case useDefaultGrpcExceptionHandlerFunctionAsFallback
grpc/src/test/java/com/linecorp/armeria/internal/common/grpc/TestServiceImpl.java
Outdated
Show resolved
Hide resolved
…the most first of exception-handling
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.
Overall looks good. Left minor comments on testing.
.../src/test/java/com/linecorp/armeria/common/grpc/GrpcExceptionHandlerFunctionBuilderTest.java
Outdated
Show resolved
Hide resolved
.../src/test/java/com/linecorp/armeria/common/grpc/GrpcExceptionHandlerFunctionBuilderTest.java
Outdated
Show resolved
Hide resolved
.../src/test/java/com/linecorp/armeria/common/grpc/GrpcExceptionHandlerFunctionBuilderTest.java
Outdated
Show resolved
Hide resolved
.../src/test/java/com/linecorp/armeria/common/grpc/GrpcExceptionHandlerFunctionBuilderTest.java
Outdated
Show resolved
Hide resolved
…ionHandlerFunctionBuilderTest.java Co-authored-by: Ikhun Um <ih.pert@gmail.com>
…ionHandlerFunctionBuilderTest.java Co-authored-by: Ikhun Um <ih.pert@gmail.com>
…ionHandlerFunctionBuilderTest.java Co-authored-by: Ikhun Um <ih.pert@gmail.com>
…ionHandlerFunctionBuilderTest.java Co-authored-by: Ikhun Um <ih.pert@gmail.com>
Applied feedback, Thanks. |
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.
Very nice! Thanks, @jaeseung-bae! 🙇♂️🚀
grpc/src/main/java/com/linecorp/armeria/internal/common/grpc/HttpStreamDeframer.java
Outdated
Show resolved
Hide resolved
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.
Basically it looks great! Left few comments. 😉
if (exceptionHandler != null) { | ||
option(EXCEPTION_HANDLER.newValue(exceptionHandler)); | ||
if (exceptionHandler == null) { | ||
exceptionHandler = GrpcExceptionHandlerFunction.ofDefault(); |
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 believe that we shouldn't set the property while building an instance:
GrpcExceptionHandlerFunction exceptionHandler;
if (this.exceptionHandler == null) {
exceptionHandler = GrpcExceptionHandlerFunction.ofDefault();
} else {
exceptionHandler = this.exceptionHandler.orElse(GrpcExceptionHandlerFunction.ofDefault());
}
exceptionHandler = new UnwrappingGrpcExceptionHandleFunction(exceptionHandler);
option(EXCEPTION_HANDLER.newValue(exceptionHandler));
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.
Currently, exceptionHandler is passed through ClientBuilderParams params
for instantiating ArmeriaChannel
. This look like a current way to pass parameters by ClientBuilderParams
and so exceptionHandler should be set. I may introduce exceptionHandler as new constructor parameter but I'm not sure that is right to do. Do you have any idea on this?
armeria/grpc/src/main/java/com/linecorp/armeria/internal/client/grpc/ArmeriaChannel.java
Lines 104 to 127 in 8ab4284
ArmeriaChannel(ClientBuilderParams params, | |
HttpClient httpClient, | |
MeterRegistry meterRegistry, | |
SessionProtocol sessionProtocol, | |
SerializationFormat serializationFormat, | |
@Nullable GrpcJsonMarshaller jsonMarshaller, | |
Map<MethodDescriptor<?, ?>, String> simpleMethodNames) { | |
this.params = params; | |
this.httpClient = httpClient; | |
this.meterRegistry = meterRegistry; | |
this.sessionProtocol = sessionProtocol; | |
this.serializationFormat = serializationFormat; | |
this.jsonMarshaller = jsonMarshaller; | |
this.simpleMethodNames = simpleMethodNames; | |
final ClientOptions options = options(); | |
maxOutboundMessageSizeBytes = options.get(GrpcClientOptions.MAX_OUTBOUND_MESSAGE_SIZE_BYTES); | |
maxInboundMessageSizeBytes = maxInboundMessageSizeBytes(options); | |
unsafeWrapResponseBuffers = options.get(GrpcClientOptions.UNSAFE_WRAP_RESPONSE_BUFFERS); | |
useMethodMarshaller = options.get(GrpcClientOptions.USE_METHOD_MARSHALLER); | |
compressor = options.get(GrpcClientOptions.COMPRESSOR); | |
decompressorRegistry = options.get(GrpcClientOptions.DECOMPRESSOR_REGISTRY); | |
credentials0 = options.get(GrpcClientOptions.CALL_CREDENTIALS); | |
exceptionHandler = options.get(GrpcClientOptions.EXCEPTION_HANDLER); |
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.
The exceptionHandler
is retrieved from options
so we don't need to add exceptionHandler
to the constructor parameter:
armeria/grpc/src/main/java/com/linecorp/armeria/internal/client/grpc/ArmeriaChannel.java
Line 127 in 8ab4284
exceptionHandler = options.get(GrpcClientOptions.EXCEPTION_HANDLER); |
I also realized that we have to create a new exceptionHandler
only when it's set:
public <T> T build(Class<T> clientType) {
requireNonNull(clientType, "clientType");
final List<ClientInterceptor> clientInterceptors = interceptors.build();
if (!clientInterceptors.isEmpty()) {
option(INTERCEPTORS.newValue(clientInterceptors));
}
if (exceptionHandler != null) {
option(EXCEPTION_HANDLER.newValue(new UnwrappingGrpcExceptionHandleFunction(
exceptionHandler.orElse(GrpcExceptionHandlerFunction.of()))));
}
....
}
public static final ClientOption<GrpcExceptionHandlerFunction> EXCEPTION_HANDLER =
ClientOption.define("EXCEPTION_HANDLER", new UnwrappingGrpcExceptionHandleFunction(
GrpcExceptionHandlerFunction.of()));
@@ -173,8 +172,7 @@ public final class GrpcClientOptions { | |||
* to a gRPC {@link Status}. | |||
*/ | |||
public static final ClientOption<GrpcExceptionHandlerFunction> EXCEPTION_HANDLER = | |||
ClientOption.define("EXCEPTION_HANDLER", | |||
(ctx, cause, metadata) -> GrpcStatus.fromThrowable(cause)); | |||
ClientOption.define("EXCEPTION_HANDLER", GrpcExceptionHandlerFunction.ofDefault()); |
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.
We don't use UnwrappingGrpcExceptionHandleFunction
because this value is never used. Is that correct?
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.
UnwrappingGrpcExceptionHandleFunction
should be the outermost handler so we don't use it here.
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.
Then, probably need to add a comment for that?
GrpcExceptionHandlerFunction.ofDefault() isn't used because the actual exceptionHandler is set while building a gRPC client in GrpcClientBuilder.
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.
Added comment, @minwoox can you check it again? Thanks,
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.
Based on this change, we have to use it now.
Sorry but could you revert 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.
Okay, I'll revert it
grpc/src/main/java/com/linecorp/armeria/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
grpc/src/main/java/com/linecorp/armeria/common/grpc/DefaultGrpcExceptionHandlerFunction.java
Outdated
Show resolved
Hide resolved
* Returns the default {@link GrpcExceptionHandlerFunction}. | ||
*/ | ||
@UnstableApi | ||
static GrpcExceptionHandlerFunction ofDefault() { |
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.
Recently, we just use of
for the default instance.
static GrpcExceptionHandlerFunction ofDefault() { | |
static GrpcExceptionHandlerFunction of() { |
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.
Applied feedback, Thanks.
...in/java/com/linecorp/armeria/internal/common/grpc/UnwrappingGrpcExceptionHandleFunction.java
Outdated
Show resolved
Hide resolved
private final GrpcExceptionHandlerFunction delegate; | ||
|
||
public UnwrappingGrpcExceptionHandleFunction(GrpcExceptionHandlerFunction handlerFunction) { | ||
this.delegate = handlerFunction; |
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.
nit:
this.delegate = handlerFunction; | |
delegate = handlerFunction; |
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.
Applied feedback, Thanks.
return delegate.apply(ctx, t, metadata); | ||
} | ||
|
||
private Throwable peelAndUnwrap(Throwable t) { |
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.
nit:
private Throwable peelAndUnwrap(Throwable t) { | |
private static Throwable peelAndUnwrap(Throwable t) { |
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.
Applied feedback, Thanks.
grpc/src/main/java/com/linecorp/armeria/internal/server/grpc/AbstractServerCall.java
Show resolved
Hide resolved
if (exceptionHandler == null) { | ||
exceptionHandler = GrpcExceptionHandlerFunction.ofDefault(); | ||
} else { | ||
exceptionHandler = exceptionHandler.orElse(GrpcExceptionHandlerFunction.ofDefault()); |
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.
ditto
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.
Is this ditto to #5571 (comment)?
I replied to #5571 (comment)?.
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.
Yes we can probably do:
GrpcExceptionHandlerFunction grpcExceptionHandler;
if (exceptionMappingsBuilder != null) {
grpcExceptionHandler = exceptionMappingsBuilder.build().orElse(GrpcExceptionHandlerFunction.of());
} else if (exceptionHandler != null) {
grpcExceptionHandler = exceptionHandler.orElse(GrpcExceptionHandlerFunction.of());;
} else {
grpcExceptionHandler = GrpcExceptionHandlerFunction.of();
}
grpcExceptionHandler = new UnwrappingGrpcExceptionHandleFunction(grpcExceptionHandler);
registryBuilder.setDefaultExceptionHandler(grpcExceptionHandler);
if (interceptors != null) {
final HandlerRegistry.Builder newRegistryBuilder = new HandlerRegistry.Builder();
final ImmutableList<ServerInterceptor> interceptors = this.interceptors.build();
for (Entry entry : registryBuilder.entries()) {
final MethodDescriptor<?, ?> methodDescriptor = entry.method();
final ServerServiceDefinition intercepted =
ServerInterceptors.intercept(entry.service(), interceptors);
newRegistryBuilder.addService(entry.path(), intercepted, methodDescriptor, entry.type(),
entry.additionalDecorators());
}
newRegistryBuilder.setDefaultExceptionHandler(grpcExceptionHandler);
handlerRegistry = newRegistryBuilder.build();
} else {
handlerRegistry = registryBuilder.build();
}
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.
Applied feedback, Thank.
Code gets cleaner :)
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.
Basically it looks great! Left a few comments. 😉
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.
LGTM once @minwoox's comments are addressed. Thanks, @jaeseung-bae!
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 once @minwoox 's comments are addressed 👍 👍 👍
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.
Just two nits. 😉
Thanks a lot, @jaeseung-bae!
grpc/src/main/java/com/linecorp/armeria/client/grpc/GrpcClientOptions.java
Outdated
Show resolved
Hide resolved
...in/java/com/linecorp/armeria/internal/common/grpc/UnwrappingGrpcExceptionHandleFunction.java
Outdated
Show resolved
Hide resolved
…Options.java Co-authored-by: minux <songmw725@gmail.com>
…nwrappingGrpcExceptionHandleFunction.java Co-authored-by: minux <songmw725@gmail.com>
@jaeseung-bae, 👍 👍 👍 |
) Motivation: - Closes line#5550 Modifications: - `GrpcStatus` implements `GrpcExceptionHandlerFunction` - Rename `GrpcStatus` to `DefaultGrpcExceptionHandlerFunction` Result: - Closes line#5550 - GrpcClientBuilder uses `DefaultGrpcExceptionHandlerFunction` as default - GrpcService can use `DefaultGrpcExceptionHandlerFunction` for its `exceptionHandler` <!-- Visit this URL to learn more about how to write a pull request description: https://armeria.dev/community/developer-guide#how-to-write-pull-request-description -->
Motivation:
GrpcStatus
implementGrpcExceptionHandlerFunction
#5550Modifications:
GrpcStatus
implementsGrpcExceptionHandlerFunction
GrpcStatus
toDefaultGrpcExceptionHandlerFunction
Result:
GrpcStatus
implementGrpcExceptionHandlerFunction
#5550DefaultGrpcExceptionHandlerFunction
as defaultDefaultGrpcExceptionHandlerFunction
for itsexceptionHandler