I have a Golang application that I deploy as an app engine standard version with manual scaling. When I deploy a new version, the application receives a GET request to the /_ah/stop endpoint. The documentation only briefly mentions requests to this endpoint:
When instances are stopped, an /_ah/stop request appears in the logs. If there is an /_ah/stop handler or a registered shutdown hook, it has 30 seconds to complete before shutdown occurs.
Regardless of what I do, my handler returns a 500, but only when deploying. The error contains a “line” field with a “logMessage” that says “Process terminated because the backend was stopped.”. (I don’t think this is actually true, since I see logging from the service from after this message.)
I have tried many variations for the stop handler, but even when the handler does nothing but reply with a 200 OK, the handler returns a 500 when the previous version is stopped when I deploy.
Minimal reproducible example:
main.go:
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/_ah/start", func(w http.ResponseWriter, r *http.Request) {})
mux.HandleFunc("/_ah/stop", stopHandler)
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
server.ListenAndServe()
}
func stopHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Returning from stop handler")
}
app.yaml:
runtime: go122
service: my-service
handlers:
- url: /.*
script: auto
manual_scaling:
instances: 1
instance_class: B1
First deploy it with “gcloud app deploy”. Then run “gcloud app deploy” again so that the previous instance gets shut down. I see a 500 response from “/_ah/stop” in the request logs, and the line “Returning from log handler” 4 ms after that.
Note that the 500 response takes 5ms, so it’s not the case that the server doesn’t respond in 30 seconds. An example of how to do a graceful shutdown (e.g. one that doesn’t cause errors) would be appreciated.