Skip to content

Commit 7afafad

Browse files
authored
docs: add v5.5 release blog post (#3497)
* docs: add v5.5 release blog post * docs: clarify update methods use match + optimistic locking in Options list * wip Signed-off-by: Attila Mészáros <a_meszaros@apple.com> * wip Signed-off-by: Attila Mészáros <a_meszaros@apple.com> --------- Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent 645c77b commit 7afafad

1 file changed

Lines changed: 135 additions & 0 deletions

File tree

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
title: Version 5.5 Released!
3+
date: 2026-07-17
4+
author: >-
5+
[Attila Mészáros](https://github.com/csviri)
6+
---
7+
8+
We're pleased to announce the release of Java Operator SDK v5.5.0! This minor version reworks how
9+
the framework filters the events caused by a controller's own writes, making it more correct and
10+
more efficient, and exposes a richer, matcher-aware `ResourceOperations` API. There are **no
11+
breaking API changes**, but there is one behavioral change around `UpdateControl` — see the
12+
migration notes.
13+
14+
If you are running on version `5.3.x` or `5.4.x` upgrade is strongly recommend!
15+
16+
## Key Features
17+
18+
### Matcher-based updates in `ResourceOperations`
19+
20+
`ResourceOperations` (available from the reconciliation `Context` via `context.resourceOperations()`)
21+
now offers a complete, consistent family of update/patch/create methods for every write strategy —
22+
**server-side apply, update (PUT), JSON Patch (RFC 6902) and JSON Merge Patch (RFC 7386)** — each
23+
available for the whole resource and the `status` subresource, and with dedicated `primary`
24+
variants.
25+
26+
Every method comes in two flavors: a default one, and one taking an `Options` argument that controls
27+
how the resulting own event is handled:
28+
29+
```java
30+
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context) {
31+
makeStatusChanges(webPage);
32+
// updates the status, filters the own event, and skips the write entirely if nothing changed
33+
context.resourceOperations().serverSideApplyPrimaryStatus(webPage);
34+
return UpdateControl.noUpdate();
35+
}
36+
```
37+
38+
By default these operations **match the desired state against the actual (cached) state before
39+
writing**: if they already match, the write is skipped; otherwise the write is performed and its own
40+
event is filtered. This is the most efficient option — it covers full event filtering *and* avoids a
41+
request to the Kubernetes API server when nothing changed. Default matchers are provided for every
42+
operation type; when one does not fit, supply your own via `Options.matchAndFilter(matcher)`.
43+
44+
`Options` exposes the available strategies:
45+
46+
- `matchAndFilter(...)` / `matchAndFilterWithDefaultMatcher(...)` — match, then write-and-filter only
47+
if needed. This is the default for the server-side apply and patch methods.
48+
- `filterWithOptimisticLocking()` — filter the own event; the write must use optimistic locking,
49+
otherwise an `IllegalArgumentException` is thrown. The matcher / `updateType` overloads also skip
50+
the write when the desired state already matches; this match + optimistic locking combination is
51+
the default for the PUT `update` methods.
52+
- `cacheOnly()` — only cache the response (read-cache-after-write consistency), no filtering.
53+
- `forceFilterEvents()` — always filter (mostly internal usage). Assumes resource was matched before
54+
or update is done using optimistic locking.
55+
56+
> **Correctness note**: filtering an own event is only safe if the framework can tell an own write
57+
> apart from a concurrent third-party write. This requires **either** a matcher **or** optimistic
58+
> locking; otherwise a concurrent external update inside the filter window may be missed until the
59+
> next resync.
60+
61+
### More correct own-event filtering (no-op update edge case)
62+
63+
The read-cache-after-write own-event filter has been reworked to fix an edge case where a legitimate
64+
external change could be filtered out together with a controller's own **no-op** update — for
65+
example, when the spec was changed externally while the controller patched its status and that status
66+
patch turned out to be a no-op. The new matcher-based operations avoid issuing such no-op writes in
67+
the first place, and the filtering itself is now correct in these concurrent scenarios.
68+
69+
## Additional Improvements
70+
71+
- **`GenericKubernetesResourceMatcher.matchStatus(...)`**: a status-only counterpart to `match(...)`
72+
that compares just the `/status` subtree.
73+
- **New `Matcher` SPI**: `io.javaoperatorsdk.operator.api.reconciler.matcher.Matcher` lets you plug a
74+
custom matching strategy into `Options.matchAndFilter(...)`.
75+
- **Quieter logs for reconciler-handled errors**: when `updateErrorStatus(...)` returns any
76+
`ErrorStatusUpdateControl` other than `defaultErrorProcessing()`, the error is treated as handled
77+
by the reconciler and logged at `DEBUG` instead of the `Uncaught error during event processing`
78+
`WARN`. Native retry (including `@GradualRetry` exponential backoff) is unchanged, so a reconciler
79+
can keep retrying a recoverable condition without spamming warnings. Return
80+
`defaultErrorProcessing()` to keep the previous behavior.
81+
- **Startup-latency metric**: a new `Metrics.eventProcessingStarted(Controller)` callback fires when
82+
a controller's event processor begins accepting events (including after a deferred start such as
83+
winning leader election). The Micrometer implementations record a per-controller gauge with the JVM
84+
uptime at that moment, making operator startup latency measurable.
85+
- Extensive integration tests covering every `ResourceOperations` update/patch operation (primary,
86+
status, and secondary resources) against a real cluster.
87+
88+
## Migration Notes
89+
90+
There are **no breaking API changes**; existing code compiles and runs unchanged. However:
91+
92+
### `UpdateControl` no longer filters own events by default
93+
94+
Returning an `UpdateControl` (or `ErrorStatusUpdateControl`) still updates the resource and keeps the
95+
cache read-after-write consistent, but it **no longer filters the resulting own event by default**
96+
so the write may cause an additional reconciliation (which should be idempotent). This change fixes correctness edge
97+
cases where an event that should have propagated was previously swallowed.
98+
99+
If you relied on the previous filtering, perform the update through `ResourceOperations` and return
100+
`UpdateControl.noUpdate()`:
101+
102+
```java
103+
// before (v5.4)
104+
resource.setStatus(new MyStatus().setReady(true));
105+
return UpdateControl.patchStatus(resource);
106+
107+
// after (v5.5) — filter the own event explicitly
108+
resource.setStatus(new MyStatus().setReady(true));
109+
context.resourceOperations().serverSideApplyPrimaryStatus(resource);
110+
return UpdateControl.noUpdate();
111+
```
112+
113+
See the [migration guide](/docs/migration/v5-5-migration) for details.
114+
115+
## Getting Started
116+
117+
```xml
118+
<dependency>
119+
<groupId>io.javaoperatorsdk</groupId>
120+
<artifactId>operator-framework</artifactId>
121+
<version>5.5.0</version>
122+
</dependency>
123+
```
124+
125+
## All Changes
126+
127+
See the [comparison view](https://github.com/operator-framework/java-operator-sdk/compare/v5.4.0...v5.5.0)
128+
for the full list of changes.
129+
130+
## Feedback
131+
132+
Please report issues or suggest improvements on our
133+
[GitHub repository](https://github.com/operator-framework/java-operator-sdk/issues).
134+
135+
Happy operator building! 🚀

0 commit comments

Comments
 (0)