feat(handler): Implement per-method timeouts with proto extensions#909
feat(handler): Implement per-method timeouts with proto extensions#909huyquanha wants to merge 9 commits intoconnectrpc:mainfrom
Conversation
| @@ -0,0 +1,9 @@ | |||
| version: v2 | |||
| name: buf.build/connectrpc/protoc-gen-connect-go | |||
There was a problem hiding this comment.
A name is needed so we can buf push it eventually.
I'm not that much of a Buf expert so not really sure if the lint/breaking rules make sense, I simply copied from the root buf.yaml.
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
Signed-off-by: Kevin Ha <hahuyquan1997@gmail.com>
5d4899f to
83489cd
Compare
| - path: proto | ||
| # this must be declared as a module in the same workspace as "proto", | ||
| # so it can import symbols from annotations.proto. | ||
| - path: internal/testdata/methodtimeouts |
There was a problem hiding this comment.
presumably we could also add all the other testdata modules here too, but it's not strictly required right now.
Signed-off-by: Huy Quan (Kevin) Ha <hahuyquan1997@gmail.com>
|
@huyquanha, while this is a neat idea, it does not belong in this core repo. This is too opinionated about the means of configuration and adds too much machinery into the core. IMO, this sort of extension of the core connect-go functionality really belongs in a 3rd-party library. Even if we in the connectrpc organization wanted to offer it, it would be a separate repo, not baked into this core repo. So I think you'd be best off for now moving this code into a 3rd-party library. You can create a different package hierarchy for the Protobuf files based on it living in a separate organization (and then you can push the definitions to buf.build from that other repo). And you can also reserve your own custom option number from the Protobuf registry. As far as the actual behavior of applying the timeouts, you should be able to do this from an interceptor. An accessor/constructor for this interceptor would likely be the only API needed in this 3rd-party library. Instead of augmenting the |
|
Hey @jhump 👋 Thanks for the suggestion! However, I'm not sure the interceptor approach will work atm. There's no way, afaict, to get access to the |
|
Hey @huyquanha, you may find the https://pkg.go.dev/connectrpc.com/authn package as a useful reference. It wraps as HTTP middleware to ensure auth is handled before message decoding. It also needs to infer the protocol. This technique could be used to apply the timeouts on the ResponseController before invoking the connect-go handler. Otherwise you can also propagate the ResponseController through the context and apply timeouts in the interceptor. |
Context
See issue: #879
Intent
This implementation draws inspirations from the grpc-gateway openapiv2 options. Users can specify a method-level option (like
idempotency_level, only difference is this one isn't a built-in field) to set custom read/write timeouts for that handler method.protoc-gen-connect-gothen injects the timeouts into the generated*connect.gofile, which're propgated to the handlerServeHttpmethod, where we can invokeresponseController.SetRead/WriteDeadlineto set per-handler timeouts.An example generated code look like this
The following rules apply:
time.Time{}i.e. no deadline. This follows the same convention ashttp.Servertimeouts, and is most beneficial for streaming endpoints where we want to disable timeouts, while still let users define server-wide timeouts to protect non-streaming RPCs.Notes
If this approach sounds reasonable to you, we will need to get a unique ID for this project, so we can use as the extension field number and avoid conflicts (see comment)
I noticed there's another PR attempting to implement the same feature, however it only takes care of the handler-side logic, without a mechanism to let users inject these timeouts into each handler easily.