Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions 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.3.6-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>bootstrapper</artifactId>
Expand All @@ -32,7 +32,7 @@

<properties>
<maven-plugin-annotations.version>3.15.2</maven-plugin-annotations.version>
<maven-plugin-api.version>3.9.16</maven-plugin-api.version>
<maven-plugin-api.version>3.9.15</maven-plugin-api.version>
<templating-maven-plugin.version>3.1.0</templating-maven-plugin.version>
<maven-plugin-plugin.version>3.15.2</maven-plugin-plugin.version>
</properties>
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.3.6-SNAPSHOT</version>
<version>999-SNAPSHOT</version>
</parent>

<artifactId>caffeine-bounded-cache-support</artifactId>
Expand Down
3 changes: 3 additions & 0 deletions docs/content/en/docs/documentation/error-handling-retries.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ these features:

2. In case an exception is thrown, a retry is initiated. However, if an event is received
meanwhile, it will be reconciled instantly, and this execution won't count as a retry attempt.
If that event-triggered reconciliation also fails inside the current retry window, the
existing retry deadline is preserved rather than reset — the failure does not advance the
retry counter unless the original deadline is imminent.
3. If the retry limit is reached (so no more automatic retry would happen), but a new event
received, the reconciliation will still happen, but won't reset the retry, and will still be
marked as the last attempt in the retry info. The point (1) still holds - thus successful reconciliation will reset the retry - but no retry will happen in case of an error.
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.3.6-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.3.6-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.3.6-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.3.6-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 @@ -321,6 +321,8 @@ private <P extends HasMetadata> ResolvedControllerConfiguration<P> controllerCon
var triggerReconcilerOnAllEvents =
annotation != null && annotation.triggerReconcilerOnAllEvents();

var defaultFilters = annotation == null || annotation.defaultFilters();

InformerConfiguration<P> informerConfig =
InformerConfiguration.builder(resourceClass)
.initFromAnnotation(annotation != null ? annotation.informer() : null, context)
Expand All @@ -341,7 +343,8 @@ private <P extends HasMetadata> ResolvedControllerConfiguration<P> controllerCon
dependentFieldManager,
this,
informerConfig,
triggerReconcilerOnAllEvents);
triggerReconcilerOnAllEvents,
defaultFilters);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,8 @@ default boolean triggerReconcilerOnAllEvent() {
default boolean triggerReconcilerOnAllEvents() {
return false;
}

default boolean isDefaultFilters() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
private Map<DependentResourceSpec, Object> configurations;
private final InformerConfiguration<R>.Builder config;
private boolean triggerReconcilerOnAllEvents;
private boolean defaultFilters;

private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
this.finalizer = original.getFinalizerName();
Expand All @@ -59,6 +60,7 @@ private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
this.name = original.getName();
this.fieldManager = original.fieldManager();
this.triggerReconcilerOnAllEvents = original.triggerReconcilerOnAllEvents();
this.defaultFilters = original.isDefaultFilters();
}

public ControllerConfigurationOverrider<R> withFinalizer(String finalizer) {
Expand Down Expand Up @@ -186,6 +188,11 @@ public ControllerConfigurationOverrider<R> withTriggerReconcilerOnAllEvents(
return this;
}

public ControllerConfigurationOverrider<R> withDefaultFilters(boolean defaultFilters) {
this.defaultFilters = defaultFilters;
return this;
}

/**
* Sets a max page size limit when starting the informer. This will result in pagination while
* populating the cache. This means that longer lists will take multiple requests to fetch. See
Expand Down Expand Up @@ -231,6 +238,7 @@ public ControllerConfiguration<R> build() {
original.getConfigurationService(),
config.buildForController(),
triggerReconcilerOnAllEvents,
defaultFilters,
original.getWorkflowSpec().orElse(null));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class ResolvedControllerConfiguration<P extends HasMetadata>
private final ConfigurationService configurationService;
private final String fieldManager;
private final boolean triggerReconcilerOnAllEvents;
private final boolean defaultFilters;
private WorkflowSpec workflowSpec;

public ResolvedControllerConfiguration(ControllerConfiguration<P> other) {
Expand All @@ -61,6 +62,7 @@ public ResolvedControllerConfiguration(ControllerConfiguration<P> other) {
other.getConfigurationService(),
other.getInformerConfig(),
other.triggerReconcilerOnAllEvents(),
other.isDefaultFilters(),
other.getWorkflowSpec().orElse(null));
}

Expand All @@ -77,6 +79,7 @@ public ResolvedControllerConfiguration(
ConfigurationService configurationService,
InformerConfiguration<P> informerConfig,
boolean triggerReconcilerOnAllEvents,
boolean defaultFilters,
WorkflowSpec workflowSpec) {
this(
name,
Expand All @@ -90,7 +93,8 @@ public ResolvedControllerConfiguration(
fieldManager,
configurationService,
informerConfig,
triggerReconcilerOnAllEvents);
triggerReconcilerOnAllEvents,
defaultFilters);
setWorkflowSpec(workflowSpec);
}

Expand All @@ -106,7 +110,8 @@ protected ResolvedControllerConfiguration(
String fieldManager,
ConfigurationService configurationService,
InformerConfiguration<P> informerConfig,
boolean triggerReconcilerOnAllEvents) {
boolean triggerReconcilerOnAllEvents,
boolean defaultFilters) {
this.informerConfig = informerConfig;
this.configurationService = configurationService;
this.name = ControllerConfiguration.ensureValidName(name, associatedReconcilerClassName);
Expand All @@ -120,6 +125,7 @@ protected ResolvedControllerConfiguration(
ControllerConfiguration.ensureValidFinalizerName(finalizer, getResourceTypeName());
this.fieldManager = fieldManager;
this.triggerReconcilerOnAllEvents = triggerReconcilerOnAllEvents;
this.defaultFilters = defaultFilters;
}

protected ResolvedControllerConfiguration(
Expand All @@ -139,7 +145,8 @@ protected ResolvedControllerConfiguration(
null,
configurationService,
InformerConfiguration.builder(resourceClass).buildForController(),
false);
false,
true);
}

@Override
Expand Down Expand Up @@ -234,4 +241,9 @@ public String fieldManager() {
public boolean triggerReconcilerOnAllEvents() {
return triggerReconcilerOnAllEvents;
}

@Override
public boolean isDefaultFilters() {
return defaultFilters;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,88 @@ default <R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType) {

<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);

/**
* Retrieves a specific secondary resource by name and namespace from the event source identified
* by the given name.
*
* <p>This is a typed convenience over manually retrieving the {@link
* io.javaoperatorsdk.operator.processing.event.source.EventSource} and calling its cache. When
* the underlying event source implements {@link
* io.javaoperatorsdk.operator.processing.event.source.Cache}, the lookup is a direct cache lookup
* and read-cache-after-write consistent.
*
* <p>{@code eventSourceName} may be {@code null}. When {@code null} and {@code expectedType} is
* part of a managed workflow whose activation condition may not have registered the event source,
* an empty {@link Optional} is returned instead of throwing {@link
* io.javaoperatorsdk.operator.processing.event.NoEventSourceForClassException}.
*
* @param expectedType the class representing the type of secondary resource to retrieve
* @param eventSourceName the name of the event source to look in (may be {@code null})
* @param name the name of the secondary resource
* @param namespace the namespace of the secondary resource (may be {@code null} for
* cluster-scoped resources)
* @param <R> the type of secondary resource to retrieve
* @return an {@link Optional} containing the matching secondary resource, or {@link
* Optional#empty()} if none matches
* @throws io.javaoperatorsdk.operator.processing.event.NoEventSourceForClassException if no event
* source is registered for the given type and name (and no workflow activation condition
* accounts for it)
* @since 5.4.0
*/
<R extends HasMetadata> Optional<R> getSecondaryResource(
Class<R> expectedType, String eventSourceName, String name, String namespace);

/**
* Convenience overload of {@link #getSecondaryResource(Class, String, String, String)} that uses
* the primary resource's namespace.
*
* <p>If the primary resource is cluster-scoped (no namespace), the lookup is performed against
* the cluster scope. To target a specific namespace from a cluster-scoped primary, use {@link
* #getSecondaryResource(Class, String, String, String)} directly.
*
* <p>{@code eventSourceName} may be {@code null} with the same semantics as in {@link
* #getSecondaryResource(Class, String, String, String)}.
*
* @param expectedType the class representing the type of secondary resource to retrieve
* @param eventSourceName the name of the event source to look in (may be {@code null})
* @param name the name of the secondary resource (namespace inferred from the primary)
* @param <R> the type of secondary resource to retrieve
* @return an {@link Optional} containing the matching secondary resource, or {@link
* Optional#empty()} if none matches
* @since 5.4.0
*/
default <R extends HasMetadata> Optional<R> getSecondaryResource(
Class<R> expectedType, String eventSourceName, String name) {
return getSecondaryResource(
expectedType, eventSourceName, name, getPrimaryResource().getMetadata().getNamespace());
}

/**
* Retrieves a {@link Stream} of the secondary resources of the specified type from the event
* source identified by the given name. Useful when several event sources are registered for the
* same type and you need to scope retrieval to one of them, or when you want to apply a custom
* filter at the call site.
*
* <p>When the underlying event source implements {@link ResourceCache}, the stream is
* read-cache-after-write consistent.
*
* <p>{@code eventSourceName} may be {@code null} with the same semantics as in {@link
* #getSecondaryResource(Class, String, String, String)}: when {@code null} and {@code
* expectedType} is part of a managed workflow whose activation condition may not have registered
* the event source, an empty {@link Stream} is returned instead of throwing {@link
* io.javaoperatorsdk.operator.processing.event.NoEventSourceForClassException}.
*
* @param expectedType the class representing the type of secondary resources to retrieve
* @param eventSourceName the name of the event source to look in (may be {@code null})
* @param <R> the type of secondary resources to retrieve
* @return a {@link Stream} of secondary resources of the specified type
* @throws io.javaoperatorsdk.operator.processing.event.NoEventSourceForClassException if no event
* source is registered for the given type and name (and no workflow activation condition
* accounts for it)
* @since 5.4.0
*/
<R> Stream<R> getSecondaryResourcesAsStream(Class<R> expectedType, String eventSourceName);

ControllerConfiguration<P> getControllerConfiguration();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,15 @@ MaxReconciliationInterval maxReconciliationInterval() default
* documentation for further details.
*/
boolean triggerReconcilerOnAllEvents() default false;

/**
* When set to {@code false}, JOSDK will not apply its default internal update filters
* (generation- aware, finalizer-needed, marked-for-deletion) to the controller's event source.
* The user's {@link Informer#onUpdateFilter()} becomes the sole filter and has full control. To
* keep any of the default behavior, compose it explicitly using the static methods on {@link
* io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters}.
*
* @return whether JOSDK's internal update filters are applied
*/
boolean defaultFilters() default true;
}
Loading
Loading