Skip to content
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

Add option to respect the marshaller specified in gRPC MethodDescriptor #5630

Merged
merged 16 commits into from May 16, 2024

Conversation

jaeseung-bae
Copy link
Contributor

@jaeseung-bae jaeseung-bae commented Apr 22, 2024

Motivation:

Modifications:

  • New option useMethodMarshaller
    • default value is false
  • Add validate logic for GrpcServiceBuilder and GrpcClientBuilder to check that unsafeWrapDeserializedBuffer and useMethodMarshaller are mutually exclusive

Result:

  • Have new option useMethodMarshaller
  • Throw IllegalStateException when both unsafeWrapDeserializedBuffer and useMethodMarshaller are enabled

@jaeseung-bae jaeseung-bae marked this pull request as ready for review April 22, 2024 23:02
@jaeseung-bae jaeseung-bae changed the title feat: add option to respect the marshaller specified in gRPC MethodDe… Add option to respect the marshaller specified in gRPC MethodDescriptor Apr 23, 2024
@ikhoon ikhoon added new feature sprint Issues for OSS Sprint participants labels Apr 24, 2024
final TestServiceBlockingStub client =
GrpcClients.builder("http://foo.com")
.useMethodMarshaller(true)
.build(TestServiceBlockingStub.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a custom method Marshaller to ensure useMethodMarshaller() works?
We may override the method marshallers in ClientInterceptor.

class MyClientInterceptor implements ClientInterceptor {
  @Override
  public <I, O> ClientCall<I, O> interceptCall(
    MethodDescriptor<I, O> method, CallOptions callOptions, Channel next) {
    
    method.toBuilder().setRequestMarshaller(new Marshaller<I>() {
        @Override
        public InputStream stream(I value) {
            // Add a counter to ensure this method is invoked.
            // Then delegate to method.requestMashaller.stream()
        }

   }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked to ensure marshaller in MethodDescriptor is working when true for useMethodMarshaller is passed through its constructor like below.

true);
}
private static Stream<Arguments> messageMarshallerArgsWithMethodMarshaller() {
return grpcJsonMarshallerStream().map(GrpcMessageMarshallerTest::messageMarshallerWithMethodMarshaller)
.map(Arguments::of);
}
@ParameterizedTest
@MethodSource({"messageMarshallerArgs", "messageMarshallerArgsWithMethodMarshaller"})

If it's not enough, I'll try to add testcast.
What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback.
Thanks for your recommendation ClientInterceptor. It works fine.

Comment on lines 186 to 190
.useMethodMarshaller(true)
.build(TestServiceBlockingStub.class);

stub.unaryCall(SimpleRequest.getDefaultInstance());
assertThat(customMarshallerInterceptor.getSpiedMarshallerCallCnt()).isEqualTo(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we test with useMethodMarshaller(false)? We may use @ParameterizedTest

@ParameterizedTest
@CsvResouce({"true, 1", "false, 0"})
void useMethodMarshaller(boolean useMethodMarshaller, int count) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for feedback.
I've found that spy-intercepter had been called even though setting useMethodMarshaller to false.
I don't have any idea at this moment, but It seems to need modification of testcase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized we needed to implement PrototypeMarshaller for the mock mashaller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, It(PrototypeMarshaller) works.

Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there!

}
};

private static class CustomMarshallerInterceptor implements ClientInterceptor {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code style) Could we place this class at the bottom of this file so that we can see the test cases first when we open this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback. Thanks.

@@ -260,6 +276,90 @@ void enableHttpJsonTranscodingWithoutJsonSupport() {
.hasMessageContaining("enableHttpJsonTranscoding");
}

static int spiedMarshallerCallCnt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this name and use a local variable instead? I don't see this field is shared with others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback. Thanks.


@Override
public InputStream stream(SimpleRequest value) {
spiedMarshallerCallCnt++;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have two different counters instead of the unified one in case one method is called twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback. Thanks.

@ikhoon ikhoon added this to the 1.29.0 milestone Apr 26, 2024
… variable for both request and response. Add additional description for requestStreamCallCnt
Comment on lines 208 to 210
CustomMarshallerInterceptor() {
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks redundant.

Suggested change
CustomMarshallerInterceptor() {
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback, Thanks.

Comment on lines 286 to 287
final AtomicInteger requestStreamCallCnt = new AtomicInteger(0);
final AtomicInteger responseStreamCallCnt = new AtomicInteger(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: 0 is the default value if not set.

Suggested change
final AtomicInteger requestStreamCallCnt = new AtomicInteger(0);
final AtomicInteger responseStreamCallCnt = new AtomicInteger(0);
final AtomicInteger requestStreamCallCnt = new AtomicInteger();
final AtomicInteger responseStreamCallCnt = new AtomicInteger();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedback, Thanks.

Copy link
Member

@trustin trustin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some nits. Well done, @jaeseung-bae!

Copy link
Contributor

@jrhee17 jrhee17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a minor comment on testing but looks good! Thanks @jaeseung-bae 🙇 👍 🙇

};

final TestServiceImplBase testService = new TestServiceImpl(
Executors.newSingleThreadScheduledExecutor());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Executors.newSingleThreadScheduledExecutor());
CommonPools.blockingTaskExecutor());

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, looks great! 👍 Left some suggestions. 😉

@@ -399,6 +411,12 @@ public <T> T build(Class<T> clientType) {

final Object client;
final ClientOptions options = buildOptions();
if (options.get(GrpcClientOptions.UNSAFE_WRAP_RESPONSE_BUFFERS) && options.get(USE_METHOD_MARSHALLER)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move logic into enableUnsafeWrapResponseBuffers and useMethodMarshaller methods so that the exception is thrown early when the property is set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll move logic to both enableUnsafeWrapResponseBuffers() and useMethodMarshaller() method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied feedbacks, Thanks.

Copy link
Member

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work, @jaeseung-bae! 👍 👍 👍
Thanks!

@minwoox minwoox merged commit 8ab4284 into line:main May 16, 2024
15 checks passed
@minwoox
Copy link
Member

minwoox commented May 16, 2024

@jaeseung-bae 👍 👍 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature sprint Issues for OSS Sprint participants
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants