Reputation: 341
When an HTTP request sent to a cloud run service is cancelled by the initiating service, the cancelled/closed connection is not propagated to the request that is being serviced inside the cloud run container.
Example code:
package main
import (
"log"
"net/http"
"os"
"time"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
select {
case <-ctx.Done():
log.Printf("context cancelled")
case <-time.After(time.Minute):
w.Write([]byte("OK"))
log.Printf("request completed. path=%s", r.URL.Path)
}
})
log.Fatal(http.ListenAndServe(":"+port, nil))
}
Running this code locally, a curl request sent to http://localhost:8080 and then cancelled with ctrl-c will show up in the logs as "context cancelled". The same request with the service deployed in cloud run and cancelled will show up as a successful request after 1 minute in the logs.
Upvotes: 5
Views: 705
Reputation: 11816
If you use HTTP2 when you deploy the cloud run container ctx.Done()
works:
gcloud run deploy <SERVICE_NAME>\
--project <GPC_PROJECT_ID>\
--allow-unauthenticated\
--use-http2 \
-q\
--region europe-west1\
--platform managed\
--image <CONTAINER_NAME>
Full example: https://github.com/karl-gustav/minimal-sse/blob/main/main.go
Upvotes: 0
Reputation: 45224
I don't think Cloud Run offers such a guarantee today.
I am guessing this is because of an implementation detail. The external traffic to a Run service does not directly go to the container, but rather passes through one or more load balancers and proxies. These LBs/proxies may not be properly propagating the client disconnects (or simply buffering requests/responses). This would result in the behavior you’re seeing.
I will go ahead and file an internal feature request about it. Thanks for bringing it up.
Upvotes: 5