From 17188927e2b507a913fb824e62d39fd41f510c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 29 Jul 2026 18:19:16 +0200 Subject: [PATCH] fix: use a monotonic clock for the cache polling timeout `pollLocalCache` computed its deadline with `LocalTime`: var startTime = LocalTime.now(); final var timeoutTime = startTime.plus(timeoutMillis, ChronoUnit.MILLIS); while (timeoutTime.isAfter(LocalTime.now())) { `LocalTime` is a time of day and wraps at midnight, so for any call made within `timeoutMillis` of 00:00 the computed deadline is *earlier* than the current time. The loop body never runs and the method throws `OperatorException("Timeout of resource polling from cache for resource")` immediately, failing the update it was retrying even though the resource would have appeared in cache. With the default 10s timeout that is a 10-second window each day. `LocalTime.now()` is also wall-clock based, so an NTP step or a DST change can shorten or extend the timeout. Switches to `System.nanoTime()`, which is monotonic and has no wrap-around concern, using overflow-safe subtraction for the comparison. No test is added: reproducing this requires controlling the clock, and the class is already deprecated for removal. --- .../api/reconciler/PrimaryUpdateAndCacheUtils.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java index f74cd49ee7..dc6d65aa34 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java @@ -16,8 +16,7 @@ package io.javaoperatorsdk.operator.api.reconciler; import java.lang.reflect.InvocationTargetException; -import java.time.LocalTime; -import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.function.UnaryOperator; @@ -232,9 +231,8 @@ private static

P pollLocalCache( Context

context, P staleResource, long timeoutMillis, long pollDelayMillis) { try { var resourceId = ResourceID.fromResource(staleResource); - var startTime = LocalTime.now(); - final var timeoutTime = startTime.plus(timeoutMillis, ChronoUnit.MILLIS); - while (timeoutTime.isAfter(LocalTime.now())) { + final var deadlineNanos = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMillis); + while (System.nanoTime() - deadlineNanos < 0) { log.debug("Polling cache for resource: {}", resourceId); var cachedResource = context.getPrimaryCache().get(resourceId).orElseThrow(); if (!cachedResource