-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
lib/netext/grpcext: Split the gRPC module #2484
Conversation
83c999d
to
12530dd
Compare
lib/netext/grpcext/conn.go
Outdated
// TODO: should we support grpc.CallOption? | ||
func (c *Conn) Invoke(ctx context.Context, method string, md metadata.MD, req Request) (*Response, error) { |
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 support grpc.CallOption?
Yes, I think this might be a good idea, given that they are present in grpc.ClientConn.Invoke()
. Can you think of a reason why we shouldn't support them now, even if we don't use them yet?
Also, do we need a method
parameter here when we have a MethodDescriptor
in the Request
?
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.
Also, do we need a method parameter here when we have a MethodDescriptor in the Request?
Unfortunately, yes. The FullName
of the method descriptor returns the full name domain as a dot notation. Instead, Invoke wants the package.serviceName/methodName
format. I don't know if the simple replacement of the last dot with a slash could be fine.
Apparently, also the protoc generator generates the url instead of get+replace of the method descriptor's full name.
The Descriptor's Parent() method could be optimal for the descriptor-based generation but the doc says that it's optional and it could return nil
. 🤷♂️
I'm thinking if we could change the name from method
to url
like our js module's documentation does.
@@ -353,49 +253,22 @@ func (c *Client) dial( | |||
reflect bool, | |||
options ...grpc.DialOption, | |||
) error { |
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 Client.dial()
code doesn't seem it has anything to do with JavaScript, what is the reason to not move it to grpcext
?
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 opens the connection then it routes through reflection if requested from the parameter, I think this way of connecting it's a property of the js module. 🤔 It could be a good idea to change the name of the method that probably it's not accurate after the refactor because the real dialling part is now delegated to grpcext
. This method instead is mostly the core part of the Connect
method.
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.
But it seems like the vast majority of the logic related to the reflection is still can be moved to a grpcext
.
I belive we can even make a private a ReflectionClient
. What js nodule needs are the *descriptorpb.FileDescriptorSet
, so the grpcext.Conn
can has a method that tries to load them. What do your think?
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.
And by the number of the logic, the current Client.dial
is more like Client.reflect
than dial 😅
"google.golang.org/grpc/status" | ||
"google.golang.org/protobuf/encoding/protojson" | ||
"google.golang.org/protobuf/encoding/prototext" | ||
"google.golang.org/protobuf/proto" |
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.
Do you consider using github.com/gogo/protobuf/proto
which has faster mashalling/unmarshalling?
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.
Hi @cygnrh, thanks for your review.
Unfortunately, we would prefer to not include it, we are very meticulous in adding new dependencies to k6
, you can read some motivations in Dependencies.md.
We would prefer to fix allowing the marshaler and unmarshaler to be injected, it would allow us to remove also the tightly coupled JSON dependency. I opened an issue for it #2497
If you have relevant observations for the grpc module, it would be helpful to get your feedback in a new issue or in #1846.
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 haven't observed performance issue since we only did the initial test. If we do see anything as k6 gRPC being more widely adopted, I'll post in the thread #1846.
} | ||
return &Conn{ | ||
raw: conn, | ||
}, nil |
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.
how about including options in this struct so we don't have to pass options again for Invoke?
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 WithDefaultCallOptions covers this case. Could it work for you?
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'm a bit confused that options ...grpc.DialOption is passed in from Dial
and Invoke
. If options is part of the Conn struct, Invoke
can use it as a receiver function.
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.
Would you add a slice DialOption field?
type Conn struct {
Options []grpc.DialOption
raw clientConnCloser
}
and, calling the Conn.Invoke
method, would you like to not pass the Call Options?
options := []grpc.DialOption{
.....
}
conn, err := Dial(ctx, addr, options...)
err = conn.Invoke(ctx, url, md)
If yes, then the issue is mainly related to the different types involved. The eventual Conn.Options
couldn't be used on the underhood call grpc.Invoke
because the Invoke method wants the CallOption type.
Please, correct me if I misunderstood.
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 guess a User can just use https://pkg.go.dev/google.golang.org/grpc#WithDefaultCallOptions as well
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 see. They are different types of options. That makes sense.
It splits the gRPC business logic from the js/k6/grpc module to a netext package. It will be easier to extend the networking+metric features for gRPC in isolated environment and/or create extension not strictly depending on the js feature.
state := c.vu.State() | ||
if state == nil { | ||
return nil, errInvokeRPCInInitContext | ||
return nil, common.NewInitContextError("invoking RPC methods in the init context is not supported") |
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.
return nil, common.NewInitContextError("invoking RPC methods in the init context is not supported") | |
return nil, common.NewInitContextError("invoking gRPC methods in the init context is not supported") |
Maybe use this? Just for consistency?
@@ -353,49 +253,22 @@ func (c *Client) dial( | |||
reflect bool, | |||
options ...grpc.DialOption, | |||
) error { |
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.
But it seems like the vast majority of the logic related to the reflection is still can be moved to a grpcext
.
I belive we can even make a private a ReflectionClient
. What js nodule needs are the *descriptorpb.FileDescriptorSet
, so the grpcext.Conn
can has a method that tries to load them. What do your think?
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 and IMO we can continue iterating in the next release on any of the currently commented stuff
The split of the gRPC business logic from the
js/k6/grpc
module to anetext
package.It enables a simpler process for extending the networking+metric features for gRPC without the k6/js dependencies.
An example of how the API of this package can be used for creating gRPC extensions: codebien/xk6-grpc-example
Closes #2315