1
0
mirror of https://github.com/prometheus/alertmanager.git synced 2026-10-26 08:39:24 +03:00

httpserver: make /-/reload handler cancellation-safe

Fix three bugs in the reload handler identified in #5103:

1. Use a buffered error channel (size 1) so the reloader goroutine
   never blocks if the HTTP client disconnects before reading the
   result.

2. Remove the incorrect `defer close(errc)` — the handler is the
   receiver, not the sender; closing from the receiver side could
   panic the sender.

3. Wrap both the enqueue (send to reloadCh) and the reply (receive
   from errc) in select statements that also listen on
   req.Context().Done(), so a client disconnect unblocks the handler
   at either stage.

Fixes #5103

Signed-off-by: June Kim <kimjune01@gmail.com>
Signed-off-by: Solomon Jacobs <solomonjacobs@protonmail.com>
This commit is contained in:
June Kim
2026-05-09 10:08:35 -07:00
committed by Guido Trotter
parent bf3af8514d
commit 1193873419
2 changed files with 137 additions and 5 deletions

View File

@@ -29,12 +29,22 @@ func Register(r *route.Router, reloadCh chan<- chan error) {
r.Get("/metrics", promhttp.Handler().ServeHTTP)
r.Post("/-/reload", func(w http.ResponseWriter, req *http.Request) {
errc := make(chan error)
defer close(errc)
errc := make(chan error, 1)
reloadCh <- errc
if err := <-errc; err != nil {
http.Error(w, fmt.Sprintf("failed to reload config: %s", err), http.StatusInternalServerError)
select {
case reloadCh <- errc:
case <-req.Context().Done():
http.Error(w, req.Context().Err().Error(), http.StatusUnprocessableEntity)
return
}
select {
case err := <-errc:
if err != nil {
http.Error(w, fmt.Sprintf("failed to reload config: %s", err), http.StatusInternalServerError)
}
case <-req.Context().Done():
http.Error(w, req.Context().Err().Error(), http.StatusUnprocessableEntity)
}
})