Repository navigation
ChangeNamespaces deadlocks when joining a populated shared informer #3650
Description
Bug Report
Hi! I ran into a deadlock issue after upgrading to 5.6 because we make heavy use of "changeNamespace" to only watch resources that our operator controls. Had Copilot compile a minimal example of what we're running into.
NonSharingInformerPool appears to offer a workaround, but I thought you might still want to look into this. Maybe there's a way to have our cake (shared informers) and eat it too (no deadlocks).
What did you do?
Registered two named Secret event sources in one controller, initially watching the same namespace.
Then added a namespace containing an existing Secret to each source with changeNamespaces().
Minimal standalone reproducer:
It contains a POM and one Java class. No Spring, WireMock, Docker, custom resources, or external cluster is required.
unzip josdk-informer-deadlock.zip
cd josdk-informer-deadlock
mvn -q compile exec:javaTo reproduce with 5.6.2:
mvn -q -Djosdk.version=5.6.2 compile exec:javaThe sample starts a local API server and creates namespaces initial and added, with a Secret in added.
Two sources initially watch initial. These calls trigger the problem:
probe.sources.get(0).changeNamespaces(Set.of("initial", "added")); // returns
probe.sources.get(1).changeNamespaces(Set.of("initial", "added")); // hangsThe first run downloads the API-server binaries. On affected versions, terminate the reproducer and any remaining API-server child processes after inspection.
What did you expect to see?
Both namespace changes complete, both sources observe the Secret, and the operator can stop normally.
What did you see instead? Under which circumstances?
The second namespace change hangs. Confirmed with the attached sample on 5.6.0 and 5.6.2.
Retargeting the first Secret source...
Retargeting the second Secret source (hangs)...
A thread dump (jcmd <maven-jvm-pid> Thread.print) shows a lock cycle:
Caller: WAITING
FutureTask.get()
AbstractExecutorService.invokeAll()
ExecutorServiceManager.boundedExecuteAndWaitForAllToComplete()
InformerManager.changeNamespaces()
ManagedInformerEventSource.changeNamespaces()
- holds InformerEventSource monitor A
InformerStarter-added-Secret: BLOCKED
InformerEventSource.onAddOrUpdate()
- waits for InformerEventSource monitor A
...
SharedProcessor.addProcessorListener()
DefaultSharedIndexInformer.addEventHandlerWithResyncPeriod()
InformerWrapper.addEventHandler()
InformerManager.getEventSourceForNamespace()
InformerManager.lambda$changeNamespaces$5()
changeNamespaces() holds the source monitor while waiting for an informer-start worker.
That worker attaches a handler to the populated shared informer.
Fabric8 synchronously replays cached objects, entering onAddOrUpdate(), which needs the same monitor.
Environment
- JOSDK:
operator-framework-core5.6.0 and 5.6.2; both reproduced. - Fabric8: 7.9.0, JDK HTTP client.
- Kubernetes: Local vanilla API server from
kube-api-test7.9.0; server reports v1.35.0. - OS: macOS 27.0.1, build 26A434, arm64.
- kubectl: Client v1.35.3; not used by the reproducer.
openjdk version "25.0.2" 2026-01-20
OpenJDK Runtime Environment Homebrew (build 25.0.2)
OpenJDK 64-Bit Server VM Homebrew (build 25.0.2, mixed mode, sharing)
Possible Solution
Avoid holding the event-source monitor across a blocking task that can synchronously replay events into that source.
Any change would need to preserve synchronization with start(), stop(), and concurrent namespace changes.
Additional context
Related changes: informer pooling #3325
and parallel namespace startup #3430.
Source inspection found the same relevant pattern in main and next; those branches were not executed.
Activity
csviri commentedon Oct 21, 2026
Thank you @florianknecht , we will take a look soon!
fix: avoid deadlock when changeNamespaces joins a populated shared in…
fix: avoid deadlock when changeNamespaces joins a populated shared in…
csviri commentedon Oct 22, 2026
@florianknecht I attached the fix, tested with you reproducer, PTAL. Will release a patch release soon after merged. thank you!
fix: avoid deadlock when changeNamespaces joins a populated shared in…