Andrea Cosentino created CAMEL-25804:
----------------------------------------

             Summary: camel-pqc - the Micrometer stateful key gauge is held 
weakly and stops reporting
                 Key: CAMEL-25804
                 URL: https://issues.apache.org/jira/browse/CAMEL-25804
             Project: Camel
          Issue Type: Bug
          Components: camel-pqc
            Reporter: Andrea Cosentino


The {{camel.pqc.stateful.key.remaining}} gauge is registered against a lambda 
that nothing keeps alive, so it reports {{NaN}} once that lambda is garbage 
collected.

{{PQCMicrometerMetrics.java:71-78}}:
{code:java}
    @Override
    public void registerStatefulKeyGauge(String algorithm, LongSupplier 
remainingSupplier) {
        statefulKeyGauge = Gauge.builder(METRIC_STATEFUL_REMAINING, 
remainingSupplier, LongSupplier::getAsLong)
                .tag("algorithm", algorithm)
                .description("Remaining signatures for the stateful PQC 
signature key")
                .register(registry);
    }
{code}

Micrometer's {{Gauge.builder(String, T obj, ToDoubleFunction<T>)}} holds the 
state object *weakly*. Verified against the {{micrometer-core}} jar on disk:
{noformat}
public class io.micrometer.core.instrument.internal.DefaultGauge<T> ... {
  private final java.lang.ref.WeakReference<T> ref;
{noformat}

The only reference to the supplier is the inline lambda passed by the producer 
— {{PQCProducer.java:504-509}}:
{code:java}
            metrics.registerStatefulKeyGauge(signatureAlgorithm, () -> {
                KeyPair kp = getRuntimeKeyPair();
                return kp != null && kp.getPrivate() != null ? 
getStatefulKeyRemaining(kp.getPrivate()) : -1;
            });
{code}
Neither the producer nor {{PQCMicrometerMetrics}} stores it — the class keeps 
only the {{Gauge}}. So after the next GC the metric that tells an operator a 
one-time-use key is approaching exhaustion goes dark, silently.

h3. Two related issues in the same class

{{statefulKeyGauge}} is a single field ({{:40}}), so a second 
{{registerStatefulKeyGauge}} call leaks the first gauge rather than replacing 
it cleanly.

{{close()}} ({{:80-87}}) removes meters by id from a shared {{MeterRegistry}}, 
so stopping one producer unregisters counters still in use by another producer 
carrying the same {{operation|algorithm|outcome}} tags.

h3. Suggested fix

Keep a strong reference to the supplier in a field of {{PQCMicrometerMetrics}} 
(a map keyed by algorithm, so multiple registrations work), and make 
{{close()}} only remove meters this instance actually created.

h3. Test gap

No test asserts the gauge still reports a value after a GC, nor that two 
producers sharing a registry do not unregister each other's counters.

----
_Reported by Claude Code (AI agent) on behalf of [~oscerd]. Every code 
reference was verified against commit {{7aae27315946}} on {{main}}._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to