diff --git a/CHANGELOG.md b/CHANGELOG.md index f5cec838228..0cb7dba1dad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan We use *breaking :warning:* to mark changes that are not backward compatible (relates only to v0.y.z releases.) +### [v0.39.1](https://github.com/thanos-io/thanos/tree/release-0.39) - 2025 07 01 + +Fixes a memory leak issue on query-frontend. The bug only affects v0.39.0. + +### Fixed + +- [#8349](https://github.com/thanos-io/thanos/pull/8349) Query-Frontend: properly clean up resources +- [#8338](https://github.com/thanos-io/thanos/pull/8338) Query-Frontend: use original roundtripper + close immediately + ### [v0.39.0](https://github.com/thanos-io/thanos/tree/release-0.39) - 2025 06 25 In short: there are a bunch of fixes and small improvements. The shining items in this release are memory usage improvements in Thanos Query and shuffle sharding support in Thanos Receiver. Information about shuffle sharding support is available in the documentation. Thank you to all contributors! diff --git a/VERSION b/VERSION index 4ef2eb086f5..d2e2400ee94 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.0 +0.39.1 diff --git a/cmd/thanos/query_frontend.go b/cmd/thanos/query_frontend.go index 7579c4cb92a..96722f710f3 100644 --- a/cmd/thanos/query_frontend.go +++ b/cmd/thanos/query_frontend.go @@ -329,13 +329,13 @@ func runQueryFrontend( return err } - roundTripper, err := cortexfrontend.NewDownstreamRoundTripper(cfg.DownstreamURL, downstreamTripper) + downstreamRT, err := cortexfrontend.NewDownstreamRoundTripper(cfg.DownstreamURL, downstreamTripper) if err != nil { return errors.Wrap(err, "setup downstream roundtripper") } // Wrap the downstream RoundTripper into query frontend Tripperware. - roundTripper = tripperWare(roundTripper) + roundTripper := tripperWare(downstreamRT) // Create the query frontend transport. handler := transport.NewHandler(*cfg.CortexHandlerConfig, roundTripper, logger, nil) @@ -402,17 +402,9 @@ func runQueryFrontend( ctx, cancel := context.WithCancel(context.Background()) g.Add(func() error { - var firstRun = true - for { - if !firstRun { - select { - case <-ctx.Done(): - return nil - case <-time.After(10 * time.Second): - } - } + doCheckDownstream := func() (rerr error) { timeoutCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() @@ -422,23 +414,33 @@ func runQueryFrontend( return errors.Wrap(err, "creating request to downstream URL") } - resp, err := roundTripper.RoundTrip(req) + resp, err := downstreamRT.RoundTrip(req) if err != nil { - level.Warn(logger).Log("msg", "failed to reach downstream URL", "err", err, "readiness_url", readinessUrl) - statusProber.NotReady(err) - firstRun = false - continue + return errors.Wrapf(err, "roundtripping to downstream URL %s", readinessUrl) } - runutil.ExhaustCloseWithLogOnErr(logger, resp.Body, "downstream health check response body") + defer runutil.CloseWithErrCapture(&rerr, resp.Body, "downstream health check response body") if resp.StatusCode/100 == 4 || resp.StatusCode/100 == 5 { - level.Warn(logger).Log("msg", "downstream URL returned an error", "status_code", resp.StatusCode, "readiness_url", readinessUrl) - statusProber.NotReady(errors.Errorf("downstream URL %s returned an error: %d", readinessUrl, resp.StatusCode)) - firstRun = false - continue + return errors.Errorf("downstream URL %s returned an error: %d", readinessUrl, resp.StatusCode) + } + + return nil + } + for { + if !firstRun { + select { + case <-ctx.Done(): + return nil + case <-time.After(10 * time.Second): + } } + firstRun = false - statusProber.Ready() + if err := doCheckDownstream(); err != nil { + statusProber.NotReady(err) + } else { + statusProber.Ready() + } } }, func(err error) { cancel()