Now I did something like this:
func contextHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithCancel(r.Context())
ctx, cancel = context.WithTimeout(ctx, config.EnvConfig.RequestTimeout)
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
logger.Debug("message", "client connection has gone away, request will be cancelled")
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
h.ServeHTTP(w, r.WithContext(ctx))
})
}
Pls pay attention to these two lines:
ctx, cancel := context.WithCancel(r.Context())
ctx, cancel = context.WithTimeout(ctx, config.EnvConfig.RequestTimeout)
According to my tests: deliberately kill the client request
and deliberately make the request exceed the deadline
, both are working fine(i mean can receive the cancellation signal and timeout signal as expected), just my concern is: the latter cancel
function will override the previous one returned by the context.WithCancel(r.Context())
, so:
- Is it a proper way to use these two APIs together like this?
- Is it even necessary to use these two APIs together?
Please help to explain.