This is an automated email from the ASF dual-hosted git repository.

jt2594838 pushed a commit to branch optimize_prometheus_report
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/optimize_prometheus_report by 
this push:
     new 8b6d0f65435 Fix Prometheus reporter initial snapshot race
8b6d0f65435 is described below

commit 8b6d0f65435e3c5749e4578ee34eddd542e97254
Author: Tian Jiang <[email protected]>
AuthorDate: Wed Sep 2 11:14:09 2026 +0800

    Fix Prometheus reporter initial snapshot race
---
 .../reporter/prometheus/PrometheusReporter.java    | 34 +++++++++++++++++++---
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
index 0316e4fffe9..fa5695e9621 100644
--- 
a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
+++ 
b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/reporter/prometheus/PrometheusReporter.java
@@ -79,7 +79,10 @@ public class PrometheusReporter implements Reporter {
   private final AbstractMetricManager metricManager;
   private volatile ScheduledExecutorService snapshotUpdateExecutor;
   private volatile DisposableServer httpServer;
-  private volatile String metricsSnapshot = "";
+
+  /** A null snapshot means that no complete scrape has been published yet. */
+  private volatile String metricsSnapshot;
+
   private volatile ScheduledFuture<?> snapshotUpdateFuture;
 
   private static final String REALM = "metrics";
@@ -107,6 +110,8 @@ public class PrometheusReporter implements Reporter {
       LOGGER.warn(MetricsMessages.PROMETHEUS_REPORTER_ALREADY_START);
       return false;
     }
+    // A reporter can be started again after its metric manager has been reset.
+    metricsSnapshot = null;
     try {
       HttpServer serverTransport =
           HttpServer.create()
@@ -124,7 +129,7 @@ public class PrometheusReporter implements Reporter {
                             }
                             String metrics =
                                 METRIC_CONFIG.isPrometheusReporterAsyncUpdate()
-                                    ? metricsSnapshot
+                                    ? getMetricsSnapshot()
                                     : scrape();
                             return res.header(HttpHeaderNames.CONTENT_TYPE, 
"text/plain")
                                 .sendString(Mono.just(metrics));
@@ -180,14 +185,24 @@ public class PrometheusReporter implements Reporter {
                 return thread;
               });
     }
+    // Delay the first background scrape until metric sets have been bound by 
the metric service.
     snapshotUpdateFuture =
         snapshotUpdateExecutor.scheduleAtFixedRate(
-            this::updateSnapshot, 0, 
PROMETHEUS_DEFAULT_SCRAPE_INTERVAL_SECONDS, TimeUnit.SECONDS);
+            this::updateSnapshot,
+            PROMETHEUS_DEFAULT_SCRAPE_INTERVAL_SECONDS,
+            PROMETHEUS_DEFAULT_SCRAPE_INTERVAL_SECONDS,
+            TimeUnit.SECONDS);
   }
 
   private void updateSnapshot() {
     try {
-      metricsSnapshot = scrape();
+      String snapshot = scrape();
+      // Do not publish an empty scrape taken before metric sets are bound. 
The request path will
+      // synchronously scrape until the first complete snapshot is available. 
Empty snapshots are
+      // published after initialization so removed metrics are not kept in the 
cache indefinitely.
+      if (!snapshot.isEmpty() || metricsSnapshot != null) {
+        metricsSnapshot = snapshot;
+      }
     } catch (Throwable t) {
       LOGGER.error(
           MetricsMessages
@@ -196,6 +211,17 @@ public class PrometheusReporter implements Reporter {
     }
   }
 
+  private String getMetricsSnapshot() {
+    String snapshot = metricsSnapshot;
+    if (snapshot == null) {
+      snapshot = scrape();
+      if (!snapshot.isEmpty()) {
+        metricsSnapshot = snapshot;
+      }
+    }
+    return snapshot;
+  }
+
   private void stopSnapshotUpdater() {
     if (snapshotUpdateFuture != null) {
       snapshotUpdateFuture.cancel(false);

Reply via email to