-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Allow interceptors to implement their own CallOptions #1223
Comments
Have you considered carrying additional data in context (Context.WithValue) to accomplish what you need? |
@mehrdada yes, I've considered it, and I do think such per-call option tweaks should be achieved by.. well a This really doesn't seem like a massive ask, and actually would breed a nicer interface for the community of grpc-go interceptor authors to use. |
We discussed this internally and some of us have mixed feelings about using a |
@mehrdada can you provide the reasoning as to why this is bad? Not having it makes it hard to add extensions to grpc-go and build a viable ecosystem. |
@mwitkow We do not think it is necessarily "bad" as you put it. Rather, it is not how If I understand correctly, what you really want is an extensibility mechanism for adding custom hooks before and after a call. Right now, carrying additional data with That said, it might indeed be a worthy goal to consider introducing more generic custom before/after hooks and we should give it some deep thought when we get a chance, and compare the various possible designs (and whether going the shortest path and making [†] It's not clear to me how it would have negative type-safety implications relative to the suggested solution, as both options seem to have to basically deal with an |
Just to clarify, I'm not advocating exposing the In terms of type safety, I do think that having your own Moreover, this allows for much nicer call patterns that are more obvious to the user when they see stream, err := s.Client.PingList(parentCtx, goodPing, grpc_retry.WithMax(5)) instead of stream, err := s.Client.PingList(grpc_retry.ContextOption(ctx, grpc_retry.WithMax(5)), goodPing) Just to clarify: it is already possible for external developers to rely on type NoOpCallOption struct {}
func (o NoOpCallOption) before(c *callInfo) error { return nil }
func (o NoOpCallOption) after(c *callInfo) { } is to make that already-possible practice safer (and avoid things lke grpc-ecosystem/go-grpc-middleware#37). The only way to avoid this practice to be used is through making |
grpc-ecosystem/go-grpc-middleware implements retry logic and other client-side interceptors.
See an example here:
https://github.com/grpc-ecosystem/go-grpc-middleware/blob/master/retry/options.go#L94
Now, it implements it by relying on an anonymous instantiation of
grpc.CallOptions
without providing an implementation. The client-side Unary and Stream interceptors then strip them before passing them togrpc.invoke
.However, this causes panics when users use the
CallOptions
without the interceptors, see:grpc-ecosystem/go-grpc-middleware#37
I propose adding a
grpc.NoOpCallOption
that CallOptions implemented in middleware. This would implement both the privatebefore
andafter
methods without doing anything, keeping thecallInfo
private.The text was updated successfully, but these errors were encountered: