Skip to content

fix: keep a strong reference to the processing started latency gauge - #3522

Draft
csviri wants to merge 1 commit into
operator-framework:mainfrom
csviri:fix/micrometer-latency-gauge-weak-ref
Draft

fix: keep a strong reference to the processing started latency gauge#3522
csviri wants to merge 1 commit into
operator-framework:mainfrom
csviri:fix/micrometer-latency-gauge-weak-ref

Conversation

@csviri

@csviri csviri commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

eventProcessingStarted registered the gauge by handing the boxed result
of getRuntimeMXBean().getUptime() straight to registry.gauge(...):

registry.gauge(PROCESSING_STARTED_LATENCY_GAUGE, tags,
    ManagementFactory.getRuntimeMXBean().getUptime());

Micrometer only keeps a weak reference to the gauged object, so it is the
caller's job to hold a strong reference. Nothing here does, which means
the boxed Long is collectable immediately and the gauge reports NaN.
processing.started.latency therefore never carried a usable value.

controllerRegistered already handles this correctly by keeping its
AtomicIntegers in the gauges map; this method just did not follow the
same pattern.

Registers the gauge against an AtomicLong held in a longGauges map
(an AtomicInteger would overflow, uptime is in milliseconds) and
updates that holder on subsequent calls, which also stops a duplicate
gauge from being registered every time the event processor starts.

Applies the same fix to the deprecated MicrometerMetrics, which has the
identical problem.

Adds regression tests asserting the gauge keeps a non-NaN value across a
GC and that repeated calls reuse a single gauge; the first fails without
this change. Also adds the (already dependency-managed) mockito-core test
dependency to the module, which had no way to stub a Controller before.

Part of #3517

`eventProcessingStarted` registered the gauge by handing the boxed result
of `getRuntimeMXBean().getUptime()` straight to `registry.gauge(...)`:

    registry.gauge(PROCESSING_STARTED_LATENCY_GAUGE, tags,
        ManagementFactory.getRuntimeMXBean().getUptime());

Micrometer only keeps a weak reference to the gauged object, so it is the
caller's job to hold a strong reference. Nothing here does, which means
the boxed Long is collectable immediately and the gauge reports NaN.
`processing.started.latency` therefore never carried a usable value.

`controllerRegistered` already handles this correctly by keeping its
`AtomicInteger`s in the `gauges` map; this method just did not follow the
same pattern.

Registers the gauge against an `AtomicLong` held in a `longGauges` map
(an `AtomicInteger` would overflow, uptime is in milliseconds) and
updates that holder on subsequent calls, which also stops a duplicate
gauge from being registered every time the event processor starts.

Applies the same fix to the deprecated `MicrometerMetrics`, which has the
identical problem.

Adds regression tests asserting the gauge keeps a non-NaN value across a
GC and that repeated calls reuse a single gauge; the first fails without
this change. Also adds the (already dependency-managed) mockito-core test
dependency to the module, which had no way to stub a Controller before.
Copilot AI review requested due to automatic review settings July 30, 2026 09:04
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a Micrometer gauge registration bug where processing.started.latency could report NaN because the gauge target was only weakly referenced (a boxed Long with no strong owner). It aligns eventProcessingStarted with the existing “keep a strong reference” pattern used for other gauges, and adds regression tests to prevent the issue from returning.

Changes:

  • Update MicrometerMetricsV2.eventProcessingStarted to register the gauge against an AtomicLong held strongly in a longGauges map (and reuse/update it on subsequent calls).
  • Apply the same strong-reference fix to the deprecated MicrometerMetrics.
  • Add regression tests and introduce mockito-core (test scope) to enable controller stubbing in the module.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetricsV2.java Keep a strong AtomicLong reference for processing.started.latency and update it on repeated starts to avoid NaN/duplicate gauges.
micrometer-support/src/main/java/io/javaoperatorsdk/operator/monitoring/micrometer/MicrometerMetrics.java Apply the same strong-reference gauge registration approach to the deprecated metrics implementation.
micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/ProcessingStartedLatencyGaugeTest.java Add regression coverage for non-NaN gauge values after GC and reuse on repeated calls.
micrometer-support/pom.xml Add mockito-core as a test dependency for the new tests.
Comments suppressed due to low confidence (1)

micrometer-support/src/test/java/io/javaoperatorsdk/operator/monitoring/micrometer/ProcessingStartedLatencyGaugeTest.java:47

  • Same as above: uptime can be 0ms, so isPositive() can be flaky here as well; prefer a non-negative assertion.
    assertThat(gauge.value()).isNotNaN().isPositive();


var gauge = registry.find(MicrometerMetricsV2.PROCESSING_STARTED_LATENCY_GAUGE).gauge();
assertThat(gauge).isNotNull();
assertThat(gauge.value()).isNotNaN().isPositive();
Comment on lines +71 to +75
private static void forceGarbageCollection() {
for (int i = 0; i < 5; i++) {
System.gc();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants