From 5c5416f6f0075f0d7a159128c8ade74254f57003 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Mon, 5 Oct 2026 15:53:52 +0100 Subject: [PATCH] fix(web): keep the action status fetch alive when a client disconnects The status fetch used the request context. A client that dropped the connection, such as a readiness probe with a one second timeout, cancelled the fetch. The failure was then cached and every later request showed no action status. The fetch now ignores the caller cancellation and keeps its own timeout. --- internal/web/actions.go | 3 ++- internal/web/actions_test.go | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/web/actions.go b/internal/web/actions.go index 7a41e3b..a95ef96 100644 --- a/internal/web/actions.go +++ b/internal/web/actions.go @@ -158,7 +158,8 @@ func (a *Actions) statusRows(ctx context.Context, rt *actionRuntime) (map[alertR if !rt.fetched.IsZero() && a.now().Sub(rt.fetched) < statusCacheTTL { return rt.rows, rt.err } - rows, err := a.fetchStatus(ctx, rt.cfg) + // A client that disconnects mid-request must not fail the fetch that every later request reuses. + rows, err := a.fetchStatus(context.WithoutCancel(ctx), rt.cfg) if err != nil { a.log.Warn("action status unavailable", "action", rt.cfg.ID, "err", err) } diff --git a/internal/web/actions_test.go b/internal/web/actions_test.go index 522d566..29910d8 100644 --- a/internal/web/actions_test.go +++ b/internal/web/actions_test.go @@ -2,6 +2,7 @@ package web import ( "bytes" + "context" "encoding/json" "io" "log/slog" @@ -407,3 +408,15 @@ func TestRedirectDoesNotForwardToken(t *testing.T) { t.Fatal("bearer token forwarded across a redirect") } } + +func TestStatusFetchSurvivesCancelledRequest(t *testing.T) { + fh := newFakeHook(t) + fh.statBody = `[{"repo":"o/r","url":"` + alertURL + `","state":"running"}]` + h := newActionServer(t, nil, fh.srv.URL) + ctx, cancel := context.WithCancel(context.Background()) + cancel() + rows, err := h.actions.statusRows(ctx, h.actions.list[0]) + if err != nil || len(rows) != 1 { + t.Fatalf("rows=%d err=%v, want the fetch to complete despite the cancelled request", len(rows), err) + } +}