Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a04024a
chore: set next version to 999-SNAPSHOT (#3469)
csviri Jul 3, 2026
cef3be3
improve: integration test to showcase external resource state in stat…
csviri Jul 29, 2026
e179410
Informer pools (#3325)
csviri Aug 1, 2026
aacb3c5
fix: new kotlin sample parent version
csviri Aug 1, 2026
05ddbcc
fix: set configuration service for default pool (#3535)
csviri Aug 3, 2026
8ab41a3
perf: size the workflow result map from Workflow#size (#3547)
csviri Aug 11, 2026
8bdfe58
refactor: call existing helpers instead of re-implementing them (#3544)
csviri Aug 11, 2026
8a18799
test: fix flaky finalizer removal in TriggerReconcilerOnAllEventIT (#…
csviri Aug 11, 2026
2740cf6
feat: detect dependent resource API version changes (#3536)
hej090224 Aug 11, 2026
0f576f2
refactor: resolve the informer target client without a downcast (#3548)
csviri Aug 11, 2026
8329795
refactor: clean up the Kubernetes resource matchers (#3546)
csviri Aug 11, 2026
f2a5748
improve: followup PR for Informer Pools (#3541)
csviri Aug 12, 2026
7504c22
refactor: let ResourceState own the trigger-on-all-events flag (#3549)
csviri Aug 13, 2026
9065185
perf: avoid redundant work on informer event paths (#3545)
csviri Aug 17, 2026
9a53fbd
improve: log informer re-use on info level (#3569)
csviri Aug 25, 2026
c5c8b16
test: cover informer retry after a CR deserialization problem (#3558)
csviri Aug 25, 2026
5ef9d39
fix: retain recently written external resources missing from a stale …
csviri Aug 28, 2026
f2e2ef0
fix: small issue after rebase on main
csviri Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bootstrapper-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>bootstrapper</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion caffeine-bounded-cache-support/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>caffeine-bounded-cache-support</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,14 @@ public List<EventSource<?, P>> prepareEventSources(EventSourceContext<P> context
1); // setting max size for testing purposes

var es =
new InformerEventSource<>(
new InformerEventSource<ConfigMap, P>(
InformerEventSourceConfiguration.from(ConfigMap.class, primaryClass())
.withItemStore(boundedItemStore)
.withSecondaryToPrimaryMapper(
Mappers.fromOwnerReferences(
context.getPrimaryResourceClass(),
this instanceof BoundedCacheClusterScopeTestReconciler))
.build(),
context);
.build());

return List.of(es);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,41 @@ If you encounter this issue on an older Kubernetes version, consider changing yo
that resource, or even upgrading your Kubernetes version. If you encounter it on a newer Kubernetes version, please log
an issue with the JOSDK and with upstream Kubernetes.

### Detecting dependent resource API version changes (experimental)

When a dependent resource's CRD gains a new API version and the operator is upgraded to target it,
comparing `actualResource.getApiVersion()` with the desired resource's API version is not a
reliable way to detect resources that still need to be updated: the Kubernetes API server serves a
resource using the requested, served API version regardless of which version it is actually stored
as, so this comparison would always trivially match.

`KubernetesDependentResource` therefore ignores `apiVersion` when matching. To still force a
one-time update of dependent resources after such an upgrade, without triggering an update on every
reconciliation, `KubernetesDependent` provides the opt-in, experimental
`detectApiVersionChange` flag:

```java
@KubernetesDependent(detectApiVersionChange = true)
public class MyDependentResource extends CRUDKubernetesDependentResource<MyResource, MyPrimary> {
// ...
}
```

When enabled, JOSDK records the API version it applies in the `javaoperatorsdk.io/last-applied-api-version`
annotation. On subsequent reconciliations, the resource is considered mismatched (and thus updated)
if that recorded marker differs from the API version the operator currently uses - this also
covers resources that predate this feature and therefore have no marker at all. Once the resource
has been updated, the marker matches the current API version again, so no further update is
requested until the API version changes again.

This is disabled by default: existing behavior, including for resources created before this
feature existed, is unaffected unless you opt in. It does not read or infer the actual storage
version of the resource from the Kubernetes API, since that information is not reliably exposed;
it only tracks what the operator itself last applied. It is also not a replacement for
Kubernetes' [StorageVersionMigration](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/storage-version-migration/),
which addresses migrating the stored representation of resources, a concern orthogonal to this
feature.

## Telling JOSDK how to find which secondary resources are associated with a given primary resource

[`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java)
Expand Down Expand Up @@ -445,6 +480,17 @@ also be created, one per dependent resource.
See [integration test](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/dependent/externalstate/externalstatebulkdependent)
as a sample.

Note that an external resource and the state resource referencing it cannot be created atomically:
the external resource has to be created first, since its identifier is what gets stored in the
state. If the resources are fetched based on the state - which is usually the case, since the
identifier is only known from the state - a poll happening in between the two steps cannot see the
new external resource yet. JOSDK keeps such a recently created resource in the cache for the next
update to avoid creating a duplicate of it, but for a resource that takes longer to become visible,
it is recommended to resolve the actual resources from the state resources in
`BulkDependentResource.getSecondaryResources`, as done in the integration test above. The state
resources are managed by an `InformerEventSource`, thus are always up-to-date regarding the
operator's own changes.

## GenericKubernetesResource based Dependent Resources

In rare circumstances resource handling where there is no class representation or just typeless handling might be
Expand Down
2 changes: 1 addition & 1 deletion docs/content/en/docs/documentation/event-filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public List<EventSource<?, MyCustomResource>> prepareEventSources(
.withOnAddFilter(cm -> true)
.build();

return List.of(new InformerEventSource<>(informerConfiguration, context));
return List.of(new InformerEventSource<>(informerConfiguration));
}
```

Expand Down
70 changes: 68 additions & 2 deletions docs/content/en/docs/documentation/eventing.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public class WebPageReconciler implements Reconciler<WebPage> {
InformerEventSourceConfiguration.from(Deployment.class, WebPage.class)
.withLabelSelector(SELECTOR)
.build();
return List.of(new InformerEventSource<>(configuration, context));
return List.of(new InformerEventSource<>(configuration));
}

// omitted code
Expand Down Expand Up @@ -346,4 +346,70 @@ for [primary resources](https://github.com/operator-framework/java-operator-sdk/

See
also [CaffeineBoundedItemStores](https://github.com/operator-framework/java-operator-sdk/blob/main/caffeine-bounded-cache-support/src/main/java/io/javaoperatorsdk/operator/processing/event/source/cache/CaffeineBoundedItemStores.java)
for more details.
for more details.

### Sharing Informers Between Controllers (Informer Pool)

{{% alert title="Experimental" color="warning" %}}
Informer pooling is marked `@Experimental`: the feature itself is production ready, but its
configuration API may still change in a non-backwards-compatible way.
{{% /alert %}}

By default JOSDK maintains an *informer pool* so that informers are **shared** across controllers
and event sources. When several `InformerEventSource`s (whether belonging to different controllers,
or dynamically registered at runtime) watch the same resource type with an equivalent configuration,
they are all backed by a single underlying `SharedIndexInformer` instead of one informer each. This
reduces memory usage and the number of watch connections opened against the API server — which
matters in operators where many controllers watch the same secondary resource type (for example
`ConfigMap` or `Secret`).
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Two event sources share an informer when their effective informer configuration matches on all of:

- the `KubernetesClient` they watch through, compared by instance: normally every event source
resolves the operator's own client, but an event source watching another cluster brings its own
(see [multi-cluster](#informereventsource-multi-cluster-support)). Two separate client instances
never share an informer, not even when they connect to the same API server — they may differ in
credentials, impersonation or TLS material, and the informer keeps using the client it was created
from,
- the resource type (or the group/version/kind for generic resources),
- the watched namespace,
- the label, field and shard selectors,
- the configured [item store](#bounded-caches-for-informers).

The `informerListLimit` is intentionally *not* part of this identity: if two otherwise-equivalent
event sources request a different list limit, the existing informer is reused (a warning is logged
and the first-configured limit is kept). Indexers are also not part of the identity: they are
registered on the shared informer under a name qualified with the controller and event source that
added them, so index names are private to an event source and cannot collide with those of another
one. You keep looking indexes up by the name you registered, and the indexers of an event source are
removed from the shared informer when it stops using it.

The pool is reference-counted: the shared informer is created on first use and only stopped once the
last event source using it is de-registered (or its controller stops). Dynamically registering an
event source for a resource that is already backed by a running informer reuses that informer, and
the initial state already in its cache is replayed to the newly added handler.

#### Selecting the pooling strategy

The strategy is provided by the
[`InformerPool`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/pool/InformerPool.java)
configured on the `ConfigurationService`. Two implementations are available:

- [`DefaultInformerPool`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/pool/DefaultInformerPool.java)
(the default): shares informers as described above.
- [`NonSharingInformerPool`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/pool/NonSharingInformerPool.java):
never shares informers, creating a dedicated informer for every event source. Use this to opt out
of pooling and restore the pre-pooling behavior.

You can override the strategy through the `ConfigurationService`:

```java
Operator operator = new Operator(overrider ->
overrider.withInformerPool(new NonSharingInformerPool()));
```

A custom strategy has to extend
[`AbstractInformerPool`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/pool/AbstractInformerPool.java),
which is what `withInformerPool` accepts: it already creates the informers from an
`InformerClassifier` and starts them, leaving the subclass to decide only whether and how they are
shared. `InformerPool` itself is just the narrower contract that the event sources consume.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public class MyReconciler implements Reconciler<TestCustomResource> {
InformerEventSource<ConfigMap, TestCustomResource> configMapES =
new InformerEventSource<>(InformerEventSourceConfiguration.from(ConfigMap.class, TestCustomResource.class)
.withNamespacesInheritedFromController(context)
.build(), context);
.build());
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return EventSourceUtils.nameEventSources(configMapES);
}
Expand Down
7 changes: 3 additions & 4 deletions docs/content/en/docs/documentation/working-with-es-caches.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ public class WebPageReconciler implements Reconciler<WebPage> {
configMapEventSource = new InformerEventSource<>(
InformerEventSourceConfiguration.from(ConfigMap.class, WebPage.class)
.withLabelSelector(SELECTOR)
.build(),
context);
.build());

return List.of(configMapEventSource);
}
Expand Down Expand Up @@ -200,7 +199,7 @@ With this index in place, you can retrieve the target resources very efficiently
```java

InformerEventSource<Job,Cluster> clusterInformer =
new InformerEventSource(
new InformerEventSource<>(
InformerEventSourceConfiguration.from(Cluster.class, Job.class)
.withSecondaryToPrimaryMapper(
cluster ->
Expand All @@ -214,7 +213,7 @@ With this index in place, you can retrieve the target resources very efficiently
.stream()
.map(ResourceID::fromResource)
.collect(Collectors.toSet()))
.withNamespacesInheritedFromController().build(), context);
.withNamespacesInheritedFromController().build());
```

## Read-cache-after-write consistency and event filtering
Expand Down
2 changes: 1 addition & 1 deletion micrometer-support/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>micrometer-support</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion migration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>migration</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion operator-framework-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-bom</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Operator SDK - Bill of Materials</name>
<description>Java SDK for implementing Kubernetes operators</description>
Expand Down
2 changes: 1 addition & 1 deletion operator-framework-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.AbstractInformerPool;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.DefaultInformerPool;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.InformerPool;

/**
* An abstract implementation of {@link ConfigurationService} meant to ease custom implementations
Expand All @@ -35,6 +38,7 @@ public class AbstractConfigurationService implements ConfigurationService {
private KubernetesClient client;
private Cloner cloner;
private ExecutorServiceManager executorServiceManager;
private AbstractInformerPool informerPool;

protected AbstractConfigurationService(Version version) {
this(version, null);
Expand Down Expand Up @@ -190,4 +194,16 @@ public ExecutorServiceManager getExecutorServiceManager() {
}
return executorServiceManager;
}

@Override
public synchronized InformerPool informerPool() {
// cached so that all controllers backed by this ConfigurationService share the same pool and
// can therefore share the underlying informers; synchronized so concurrent first-access from
// multiple controllers cannot create (and share out) more than one pool instance
if (informerPool == null) {
informerPool = new DefaultInformerPool();
informerPool.setConfigurationService(this);
}
return informerPool;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@
import io.javaoperatorsdk.operator.api.event.DefaultEventRecorder;
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.Experimental;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig;
import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory;
import io.javaoperatorsdk.operator.processing.event.source.controller.ControllerEventSource;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.DefaultInformerPool;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.InformerPool;

/** An interface from which to retrieve configuration information. */
public interface ConfigurationService {
Expand Down Expand Up @@ -494,4 +497,27 @@ default boolean useSSAToPatchPrimaryResource() {
default boolean cloneSecondaryResourcesWhenGettingFromCache() {
return false;
}

/**
* The informer pool used to create and (when using the default, sharing pool) share the informers
* backing the event sources of all controllers managed by this {@code ConfigurationService}.
*
* <p><strong>Implementations must return the same instance on every call.</strong> The pool is
* effectively a per-{@code ConfigurationService} singleton: controllers share informers only if
* they resolve the same pool, and reference counting / informer shutdown are only correct if
* {@code getInformer} and {@code releaseInformer} operate on that same instance. This is
* intentionally not a {@code default} method, since a {@code default} could not cache the result

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Wrap the Javadoc line to stay within 100 characters.

Line 491 exceeds the Java line-length limit. Move the {@link AbstractConfigurationService} reference to the next Javadoc line.

As per coding guidelines: “Limit Java source lines to 100 characters.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java`
at line 491, Wrap the Javadoc sentence near ConfigurationService so the line
stays within 100 characters, moving the {`@link` AbstractConfigurationService}
reference to the following Javadoc line without changing the text or meaning.

Source: Coding guidelines

* and would hand out a fresh (unshared) pool on each call; {@link AbstractConfigurationService}
* provides a cached implementation backed by the default sharing pool.
*
* @return the informer pool for this configuration service
*/
@Experimental(
"Only the configuration API around informer pooling could still change in a"
+ " non-backwards-compatible way, the pooling itself is prod ready.")
default InformerPool informerPool() {
var pool = new DefaultInformerPool();
pool.setConfigurationService(this);
return pool;
Comment on lines +501 to +521

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Make informerPool() an abstract method.

Line 487 requires the same pool instance on every call. Lines 500-503 create a new pool on every call.

A custom ConfigurationService that relies on this default method will not share informers. Its releases will target different pools.

Keep the cached implementation in AbstractConfigurationService, but remove this default implementation.

Proposed fix
-  default InformerPool informerPool() {
-    var pool = new DefaultInformerPool();
-    pool.setConfigurationService(this);
-    return pool;
-  }
+  InformerPool informerPool();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* The informer pool used to create and (when using the default, sharing pool) share the informers
* backing the event sources of all controllers managed by this {@code ConfigurationService}.
*
* <p><strong>Implementations must return the same instance on every call.</strong> The pool is
* effectively a per-{@code ConfigurationService} singleton: controllers share informers only if
* they resolve the same pool, and reference counting / informer shutdown are only correct if
* {@code getInformer} and {@code releaseInformer} operate on that same instance. This is
* intentionally not a {@code default} method, since a {@code default} could not cache the result
* and would hand out a fresh (unshared) pool on each call; {@link AbstractConfigurationService}
* provides a cached implementation backed by the default sharing pool.
*
* @return the informer pool for this configuration service
*/
@Experimental(
"Only the configuration API around informer pooling could still change in a"
+ " non-backwards-compatible way, the pooling itself is prod ready.")
default InformerPool informerPool() {
var pool = new DefaultInformerPool();
pool.setConfigurationService(this);
return pool;
/**
* The informer pool used to create and (when using the default, sharing pool) share the informers
* backing the event sources of all controllers managed by this {`@code` ConfigurationService}.
*
* <p><strong>Implementations must return the same instance on every call.</strong> The pool is
* effectively a per-{`@code` ConfigurationService} singleton: controllers share informers only if
* they resolve the same pool, and reference counting / informer shutdown are only correct if
* {`@code` getInformer} and {`@code` releaseInformer} operate on that same instance. This is
* intentionally not a {`@code` default} method, since a {`@code` default} could not cache the result
* and would hand out a fresh (unshared) pool on each call; {`@link` AbstractConfigurationService}
* provides a cached implementation backed by the default sharing pool.
*
* `@return` the informer pool for this configuration service
*/
`@Experimental`(
"Only the configuration API around informer pooling could still change in a"
" non-backwards-compatible way, the pooling itself is prod ready.")
InformerPool informerPool();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java`
around lines 483 - 503, Change ConfigurationService.informerPool() from a
default method to an abstract method by removing its DefaultInformerPool
construction and configuration logic. Keep the existing cached implementation in
AbstractConfigurationService unchanged so every configuration service returns
the same pool instance.

}
Comment thread
csviri marked this conversation as resolved.
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.Operator;
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
import io.javaoperatorsdk.operator.api.reconciler.Experimental;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
import io.javaoperatorsdk.operator.processing.event.source.informer.pool.InformerPool;

@SuppressWarnings({"unused", "UnusedReturnValue"})
public class ConfigurationServiceOverrider {
Expand All @@ -54,6 +56,7 @@ public class ConfigurationServiceOverrider {
private Set<Class<? extends HasMetadata>> defaultNonSSAResource;
private Boolean useSSAToPatchPrimaryResource;
private Boolean cloneSecondaryResourcesWhenGettingFromCache;
private InformerPool informerPool;

@SuppressWarnings("rawtypes")
private DependentResourceFactory dependentResourceFactory;
Expand Down Expand Up @@ -190,6 +193,21 @@ public ConfigurationServiceOverrider withCloneSecondaryResourcesWhenGettingFromC
return this;
}

/**
* Overrides the informer pool strategy used to create/share the informers backing the event
* sources. When not set, the default (informer-sharing) pool is used.
*
* <p>Custom strategies implement {@link InformerPool}, which already takes care of creating and
* starting the informers.
*/
@Experimental(
"Only the configuration API around informer pooling could still change in a"
+ " non-backwards-compatible way, the pooling itself is prod ready.")
public ConfigurationServiceOverrider withInformerPool(InformerPool informerPool) {
this.informerPool = informerPool;
return this;
}

public ConfigurationService build() {
return new BaseConfigurationService(original.getVersion(), cloner, client) {
@Override
Expand Down Expand Up @@ -330,6 +348,15 @@ public boolean cloneSecondaryResourcesWhenGettingFromCache() {
cloneSecondaryResourcesWhenGettingFromCache,
ConfigurationService::cloneSecondaryResourcesWhenGettingFromCache);
}

@Override
public InformerPool informerPool() {
if (informerPool == null) {
return super.informerPool();
}
informerPool.setConfigurationService(this);
return informerPool;
}
};
}
}
Loading
Loading