From 39ce5434558b4f2b1d7c6863b23f402c4cab5e23 Mon Sep 17 00:00:00 2001 From: Qi Tan <16416018+TQJADE@users.noreply.github.com> Date: Thu, 18 Jun 2026 09:45:40 -0700 Subject: [PATCH 1/2] parallelize InformerManager changeNamespaces InformerManager#changeNamespaces starts informers for newly added namespaces sequentially via Set#forEach. Each source.start() call blocks up to cacheSyncTimeout waiting for cache sync, so when N namespaces are added and any of them are slow or RBAC-denied (a common case under stopOnInformerErrorDuringStartup=false), the total wall-clock is O(N * cacheSyncTimeout). The Controller holds its EventProcessor stopped across this entire call, dropping watch events with "Skipping event ... because the event processor is not started" and producing multi-minute reconcile delays after dynamic namespace updates. Align changeNamespaces with the existing parallel pattern already used by InformerManager#start (boundedExecuteAndWaitForAllToComplete on the caching executor). Wall-clock drops from O(N * timeout) to O(timeout). The sources map is already a ConcurrentHashMap, so no additional synchronization is required. Co-Authored-By: Claude Opus 4.7 (1M context) Revert "178463593 test" This reverts commit c3550e41e9bfbf3bc3619257aa0bb26ae46ac2dc. Signed-off-by: Qi Tan <16416018+TQJADE@users.noreply.github.com> --- .../source/informer/InformerManager.java | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java index a0b7938302..32e9286078 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java @@ -113,14 +113,28 @@ public void changeNamespaces(Set namespaces) { log.debug("Stopped informer {} for namespaces: {}", this, sourcesToRemove); sourcesToRemove.forEach(k -> sources.remove(k).stop()); - namespaces.forEach( - ns -> { - if (!sources.containsKey(ns)) { - final InformerWrapper source = createEventSourceForNamespace(ns); - source.start(); - log.debug("Registered new {} -> {} for namespace: {}", this, source, ns); - } - }); + var newNamespaces = + namespaces.stream().filter(ns -> !sources.containsKey(ns)).collect(Collectors.toList()); + if (newNamespaces.isEmpty()) { + return; + } + + controllerConfiguration + .getConfigurationService() + .getExecutorServiceManager() + .boundedExecuteAndWaitForAllToComplete( + newNamespaces.stream(), + ns -> { + final InformerWrapper source = createEventSourceForNamespace(ns); + source.start(); + log.debug("Registered new {} -> {} for namespace: {}", this, source, ns); + return null; + }, + ns -> + "InformerStarter-" + + ns + + "-" + + configuration.getResourceClass().getSimpleName()); } private InformerWrapper createEventSourceForNamespace(String namespace) { From 35ef37681a9140511fbd5fd8196427e50ea8e641 Mon Sep 17 00:00:00 2001 From: Qi Tan <16416018+TQJADE@users.noreply.github.com> Date: Fri, 19 Jun 2026 09:20:44 -0700 Subject: [PATCH 2/2] Address comments Signed-off-by: Qi Tan <16416018+TQJADE@users.noreply.github.com> --- .../processing/event/source/informer/InformerManager.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java index 32e9286078..bfbe17c7c8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerManager.java @@ -125,16 +125,12 @@ public void changeNamespaces(Set namespaces) { .boundedExecuteAndWaitForAllToComplete( newNamespaces.stream(), ns -> { - final InformerWrapper source = createEventSourceForNamespace(ns); + final var source = createEventSourceForNamespace(ns); source.start(); log.debug("Registered new {} -> {} for namespace: {}", this, source, ns); return null; }, - ns -> - "InformerStarter-" - + ns - + "-" - + configuration.getResourceClass().getSimpleName()); + ns -> "InformerStarter-" + ns + "-" + configuration.getResourceClass().getSimpleName()); } private InformerWrapper createEventSourceForNamespace(String namespace) {