From de793b81d074f99347fb3493a622bfed635cb595 Mon Sep 17 00:00:00 2001 From: Iwo Panowicz <27162227+impimp@users.noreply.github.com> Date: Thu, 3 Jul 2025 21:17:12 +0200 Subject: [PATCH 1/3] Fix parsing of X-Prometheus-Scrape-Timeout-Seconds header The previous implementation expected this header to be an integer, but vmagent may send it as a float. This caused incorrect handling in `mongodb_exporter`. Updated to support float values. --- exporter/exporter.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/exporter/exporter.go b/exporter/exporter.go index ac56e1a7f..ac2b7de74 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -300,20 +300,25 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) { // run for hooking up custom HTTP servers. func (e *Exporter) Handler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - seconds, err := strconv.Atoi(r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds")) - // To support older ones vmagents. - if err != nil { - seconds = 10 + scrapeTimeoutHeader := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds") + seconds := 10.0 + + if scrapeTimeoutHeader != "" { + if parsedSeconds, err := strconv.ParseFloat(scrapeTimeoutHeader, 64); err == nil { + seconds = parsedSeconds + } else { + e.logger.Info("Invalid X-Prometheus-Timeout-Scrape-Timeout-Seconds header", "error", err) + } } - seconds -= e.opts.TimeoutOffset + seconds -= float64(e.opts.TimeoutOffset) var client *mongo.Client - ctx, cancel := context.WithTimeout(r.Context(), time.Duration(seconds)*time.Second) + ctx, cancel := context.WithTimeout(r.Context(), time.Duration(seconds*float64(time.Second))) defer cancel() requestOpts := GetRequestOpts(r.URL.Query()["collect[]"], e.opts) - client, err = e.getClient(ctx) + client, err := e.getClient(ctx) if err != nil { e.logger.Error("Cannot connect to MongoDB", "error", err) } From d15be68f611b2d70073862505300d62a22fbb7e5 Mon Sep 17 00:00:00 2001 From: Iwo Panowicz <27162227+impimp@users.noreply.github.com> Date: Thu, 3 Jul 2025 21:17:20 +0200 Subject: [PATCH 2/3] Avoid stale connections by pinging on acquire The exporter was returning cached MongoDB connections without validating their health. This meant that if a connection had become unhealthy, subsequent operations would fail after a delay (serverSelectionTimeout etc), causing the entire request to be slower than it should be. This commit adds `Ping` check before returning a cached client. --- exporter/exporter.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exporter/exporter.go b/exporter/exporter.go index ac2b7de74..96c8bfa95 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -273,8 +273,13 @@ func (e *Exporter) getClient(ctx context.Context) (*mongo.Client, error) { e.clientMu.Lock() defer e.clientMu.Unlock() - // If client is already initialized, return it. + // If client is already initialized, and Ping is successful -- return it. if e.client != nil { + err := e.client.Ping(ctx, nil) + if err != nil { + return nil, fmt.Errorf("cannot connect to MongoDB: %w", err) + } + return e.client, nil } From ee2070b94d141b741ef086ca9817a78cacbf9759 Mon Sep 17 00:00:00 2001 From: I <27162227+impimp@users.noreply.github.com> Date: Mon, 7 Jul 2025 10:51:25 +0200 Subject: [PATCH 3/3] Update exporter/exporter.go Co-authored-by: Alex Demidoff --- exporter/exporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/exporter.go b/exporter/exporter.go index 96c8bfa95..d69ddff0a 100644 --- a/exporter/exporter.go +++ b/exporter/exporter.go @@ -312,7 +312,7 @@ func (e *Exporter) Handler() http.Handler { if parsedSeconds, err := strconv.ParseFloat(scrapeTimeoutHeader, 64); err == nil { seconds = parsedSeconds } else { - e.logger.Info("Invalid X-Prometheus-Timeout-Scrape-Timeout-Seconds header", "error", err) + e.logger.Info("Invalid X-Prometheus-Scrape-Timeout-Seconds header", "error", err) } } seconds -= float64(e.opts.TimeoutOffset)