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.