-
Notifications
You must be signed in to change notification settings - Fork 4.5k
client: export types implementing CallOptions for access by interceptors #1902
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
Conversation
Thank you for your pull request. Before we can look at your contribution, we need to ensure all contributors are covered by a Contributor License Agreement. After the following items are addressed, please respond with a new comment here, and the automated system will re-verify.
Regards, |
credentials/alts/utils.go
Outdated
@@ -44,7 +44,7 @@ const ( | |||
type platformError string | |||
|
|||
func (k platformError) Error() string { | |||
return fmt.Sprintf("%v is not supported", k) | |||
return fmt.Sprintf("%s is not supported", string(k)) |
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 guessing this test doesn't run in CI? This resulted in a stack overflow because this fmt.Sprintf
call effectively recursed back into this Error()
method. (I discovered this when I tried to run all tests locally, and this was the only package that failed.)
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 should be a separate PR.
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.
Done
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.
#1906 is merged. Please rebase this PR.
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.
done
Also, any idea how I kick the cla/linuxfoundation CLA check? I agreed to CLA but don't know how to re-trigger the check so that one goes green. I am pretty confident my change could not have induced the test failures. And I cannot reproduce any of them locally. Perhaps the tests are a little flaky and I got a bad run? Nothing in this branch would have introduced anything racy: it's very straight-forward replacing of a concrete type with an interface and one spot where I moved some code from one method to another. |
The Go1.9 run says |
Doh! My bad. I must admit: I didn't look at the details because I saw two jobs that both used 1.9.4, and it passed in one and failed in the other. (So I assumed it must have been some sort of flake.) @dfawley, I addressed your comments, so I think it's ready for a review now. |
4fbd53b
to
e92eae8
Compare
…an recover the configuration
e92eae8
to
6492fec
Compare
Ping? |
Sorry for the delay, and thanks for the implementation. This is, indeed, what I meant. But seeing it in practice, I'm not sure how I feel about this from a usability perspective. It may be better if the
With this version, I think users would need to do:
With the types being exported, it would be more documented as well (i.e. the exact method signatures would show up in godoc). What do you think? I'd also like to mark anything we do here as experimental, and give it some time before we decide to definitely go with that approach. |
I dig it. I didn't do it that way to start because I was worried about adding too much API surface area to support. But, admittedly, if it's documented that the thing implements a particular method, it's not too much more to just give users exported types to use, too. As far as marking it experimental, would it suffice to just document all of the new exported types like so? // This is an EXPERIMENTAL API. Or should I also make note of it in the call option factory function (since its return type is part of the experimental API)? |
Sounds good.
No; those should continue to return
But that would be optional IMO. |
a473fbe
to
d42cc48
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.
Thanks, this looks better! Please add some test cases in test/end2end_test.go. (Let me know if you need any help with that.)
@@ -250,10 +343,22 @@ func PerRPCCredentials(creds credentials.PerRPCCredentials) CallOption { | |||
// |
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.
If WithCompressor is also set, UseCompressor has higher priority.
This raises an interesting point... we have some DialOptions that also can alter per-RPC behavior. Especially WithDefaultCallOptions
.
To do this right, we should make sure there are CallOption equivalents for every appropriate DialOption, express them in terms of default CallOptions instead, and then pass those defaults along with the per-call CallOptions to the interceptors.
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 other dial options (WithMaxMsgSize
and WithCodec
) use WithDefaultCallOptions
under the hood. So exposing these all to the interceptor turned out to be pretty simple.
rpc_util.go
Outdated
// FailFastCallOption is a CallOption for indicating whether an RPC should fail | ||
// fast or not. | ||
// This is an EXPERIMENTAL API. | ||
type FailFastCallOption bool |
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 have some CallOptions that are structs and some that are not. We should unify these since they are now exported. The struct gives us a little better extensibility, so unless there's a compelling reason to use non-structs, I would prefer structs.
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.
Done
rpc_util.go
Outdated
} | ||
} | ||
|
||
// HeaderAddr returns the address where header metadata will be stored after the |
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'd prefer to export the field vs. add an accessor. It would be simpler to use, and these CallOption types are passed around by value anyway, so we don't have to worry about the interceptor modifying something inside the application (except the header/trailer/etc data directly). Would you have any concerns with 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.
That totally makes sense. The methods only made sense when relying on caller to do an interface-type-assertion to call it. With exported types, this is much better.
Since I didn't actually change behavior, it's unclear what tests you wanted me to add. I just added one that ensures that all call options (including those setup as default call options during dial) are correctly observed (and thus inspectable via exported types) by interceptors. |
d7d0145
to
be55cbd
Compare
@dfawley, PTAL |
ping |
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 great, thanks! Just one comment about comments...
rpc_util.go
Outdated
// HeaderCallOption is a CallOption for collecting response header metadata. | ||
// This is an EXPERIMENTAL API. | ||
type HeaderCallOption struct { | ||
HeaderAddr *metadata.MD |
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.
Perhaps a comment to indicate this should only be consumed after the RPC has completed would be good. (And on Trailer and Peer)
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 updated the comments. Hopefully the wording is to your liking. If not, I'm open to suggestions :)
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 @jhump!
@@ -27,6 +27,10 @@ import ( | |||
// | |||
// All errors returned by Invoke are compatible with the status package. | |||
func (cc *ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...CallOption) error { | |||
// allow interceptor to see all applicable call options, which means those | |||
// configured as defaults from dial option as well as per-call options | |||
opts = append(cc.dopts.callOptions, opts...) |
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.
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 catch! See #1948
This fixes #1495.
If I understood correctly, @dfawley, this is the approach you were suggesting. Can you take a look and let me know?