You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Called context.getSecondaryResources(resource) inside ResourceDiscriminator.
What did you expect to see?
Secondary resources.
What did you see instead? Under which circumstances?
Not sure the exact circumstances, but saw:
java.util.ConcurrentModificationException
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1792)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
at io.javaoperatorsdk.operator.processing.event.EventSources.getEventSources(EventSources.java:184)
at io.javaoperatorsdk.operator.processing.event.EventSourceManager.getResourceEventSourcesFor(EventSourceManager.java:228)
at io.javaoperatorsdk.operator.api.reconciler.DefaultContext.getSecondaryResourcesAsStream(DefaultContext.java:50)
at io.javaoperatorsdk.operator.api.reconciler.DefaultContext.getSecondaryResources(DefaultContext.java:40)
Unfortunately, baring a JDK bug, I don't see anything in the code that would cause this problem since these operations are read-only. Let us know if you manage to replicate the issue with some additional context, please.
I'm not sure I can replicate it easily. But I think I can easily demonstrate the underlying issue.
@Test
void testConcurrency() throws InterruptedException {
AtomicBoolean done = new AtomicBoolean();
while (!done.get()) {
Phaser phaser = new Phaser(2);
Map<Object, Object> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put(i, i);
}
Stream<Object> stream = map.values().stream();
Thread thread1 = new Thread(() -> {
phaser.arriveAndAwaitAdvance();
for (int i = 10; i < 20; i++) {
map.put(i, i);
}
});
Thread thread2 = new Thread(() -> {
phaser.arriveAndAwaitAdvance();
stream.collect(Collectors.toList());
});
thread2.setUncaughtExceptionHandler((t, e) -> {
if (e instanceof ConcurrentModificationException) {
e.printStackTrace(System.out);
done.set(true);
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
java.util.ConcurrentModificationException
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1792)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
This reconciler is "managed", in the sense that dependent resources are added through annotations. No event sources for this reconciler are initialized manually.
This reconciler does however have six dependent resources with activation conditions, including the dependent resource whose ResourceDiscriminator was called when this exception was thrown. I could be wrong, but I suspect this may be related to the activation conditions.
Activity
metacosm commentedon Nov 6, 2024
Unfortunately, baring a JDK bug, I don't see anything in the code that would cause this problem since these operations are read-only. Let us know if you manage to replicate the issue with some additional context, please.
matteriben commentedon Nov 6, 2024
I'm not sure I can replicate it easily. But I think I can easily demonstrate the underlying issue.
metacosm commentedon Nov 7, 2024
OK so the issue would happen when your
ResourceDiscriminatorwould be called while other event sources are still being initialized? If you are initializing your event sources manually, you could try to set the event source's priority toEventSourceStartPriority.RESOURCE_STATE_LOADERto see if this addresses the issue (you can see an example of this being used at https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalStateReconciler.java#L107).If you're not setting up sources manually, could you detail how they are set up, please? Maybe we could (should?) surface that priority setting?
matteriben commentedon Nov 7, 2024
This reconciler is "managed", in the sense that dependent resources are added through annotations. No event sources for this reconciler are initialized manually.
This reconciler does however have six dependent resources with activation conditions, including the dependent resource whose
ResourceDiscriminatorwas called when this exception was thrown. I could be wrong, but I suspect this may be related to the activation conditions.AbstractWorkflowExecutor::registerOrDeregisterEventSourceBasedOnActivation
EventSourceManager::dynamicallyRegisterEventSource
EventSourceManager::registerEventSource
EventSources::add
csviri commentedon Nov 7, 2024
Yes, event sources are added dynamically with activation condition, this will be the issue
csviri commentedon Nov 12, 2024
Added fix for both main and v5, pls take a look if it makes sense.