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

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git

commit e65489642ac3402ef23e7a3c4361d47a489213a4
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Jun 13 09:06:30 2025 +0100

    Remove micrometer gauges when data service removed
---
 .../jena/fuseki/metrics/FusekiRequestsMetrics.java | 28 ++++++++++++++--------
 .../org/apache/jena/fuseki/server/DataService.java | 16 +++++++++----
 2 files changed, 29 insertions(+), 15 deletions(-)

diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/metrics/FusekiRequestsMetrics.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/metrics/FusekiRequestsMetrics.java
index f8a8a3dcff..88efb82199 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/metrics/FusekiRequestsMetrics.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/metrics/FusekiRequestsMetrics.java
@@ -17,7 +17,9 @@
  */
 package org.apache.jena.fuseki.metrics;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import io.micrometer.core.instrument.Gauge;
 import io.micrometer.core.instrument.MeterRegistry;
@@ -35,24 +37,30 @@ public class FusekiRequestsMetrics implements MeterBinder {
     @Override
     public void bindTo(MeterRegistry registry) {
         DataService dataService = dataAccessPoint.getDataService();
+        Set<Gauge> gauges = new HashSet<>();
+
         for (Operation operation : dataService.getOperations()) {
             List<Endpoint> endpoints = dataService.getEndpoints( operation );
             for (Endpoint endpoint : endpoints) {
                 CounterSet counters = endpoint.getCounters();
                 for (CounterName counterName : counters.counters()) {
                     Counter counter = counters.get( counterName );
-
-                    Gauge.builder(
-                            "fuseki_" + counterName.getFullName(), counter, 
Counter::value )
-                            .tags( new String[] {
-                                    "dataset", dataAccessPoint.getName(),
-                                    "endpoint", endpoint.getName(),
-                                    "operation", operation.getName(),
-                                    "description", operation.getDescription()
-                            } )
-                            .register( registry );
+                    Gauge gauge =
+                        Gauge.builder(
+                                "fuseki_" + counterName.getFullName(), 
counter, Counter::value )
+                                .tags( new String[] {
+                                        "dataset", dataAccessPoint.getName(),
+                                        "endpoint", endpoint.getName(),
+                                        "operation", operation.getName(),
+                                        "description", 
operation.getDescription()
+                                } )
+                                .register( registry );
+                    gauges.add(gauge);
                 }
             }
         }
+        dataService.addShutdownHandler(dataSrv->{
+            gauges.forEach(registry::remove);
+        });
     }
 }
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
index d6753933b9..f16ad4fe16 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
@@ -58,14 +58,15 @@ public class DataService {
      * associated with. This is mainly for checking and development.
      * Usually, one {@code DataService} is associated with one {@link 
DataAccessPoint}.
      */
-    private List<DataAccessPoint> dataAccessPoints      = new ArrayList<>(1);
+    private List<DataAccessPoint> dataAccessPoints          = new 
ArrayList<>(1);
+    private List<Consumer<DataService>> shutdownHandlers    = new 
ArrayList<>(5);
 
-    private volatile DataServiceStatus state            = UNINITIALIZED;
+    private volatile DataServiceStatus state                = UNINITIALIZED;
 
     // DataService-level counters.
-    private final CounterSet    counters                = new CounterSet();
-    private final AtomicBoolean offlineInProgress       = new 
AtomicBoolean(false);
-    private final AtomicBoolean acceptingRequests       = new 
AtomicBoolean(true);
+    private final CounterSet    counters                    = new CounterSet();
+    private final AtomicBoolean offlineInProgress           = new 
AtomicBoolean(false);
+    private final AtomicBoolean acceptingRequests           = new 
AtomicBoolean(true);
 
     private DispatchFunction plainOperationChooser;
 
@@ -251,10 +252,15 @@ public class DataService {
         }
     }
 
+    public void addShutdownHandler(Consumer<DataService> action ) {
+        shutdownHandlers.add(action);
+    }
+
     /** Shutdown and never use again. */
     public synchronized void shutdown() {
         if ( state == CLOSING )
             return;
+        shutdownHandlers.forEach(action->action.accept(this));
         expel(dataset);
         dataset = null;
         state = CLOSED;

Reply via email to