The problem can be reproduced with the below simple go code snippet:
Simple go http server:
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
go func(done <-chan struct{}) {
<-done
fmt.Println("message", "client connection has gone away, request got cancelled")
}(r.Context().Done())
time.Sleep(30 * time.Second)
fmt.Fprintf(w, "Hi there, I love %s!
", r.URL.Path[1:])
}
func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Start above http server, if i send one simple GET
request with curl(postman also) like:
curl -X GET http://localhost:8080/
then press Ctrl+C
to terminate the request, then i am able to see the printed message at server side:
message client connection has gone away, request got cancelled
above is the correct behaviour i expect: to simulate the situation that when client is gone the server can capture it and then cancel all the unnecessary work as early as it can.
But when i send one POST request with request body, this expected behaviour doesn't happen, the <-done
signal was captured until the request deadline meet.
curl -X POST http://localhost:8080/ -H 'Content-Type: application/json' -d '{}'
To summarize my questions:
- Why and how the curl(postman)
GET
,POST
(with or without request body) request make such a difference? - How should i handle this case properly with go context package, i mean to capture the client is gone signal as soon as it can, and so further to cancel the server side unnecessary work to release the resources as early as it can.