Skip to content

Signal infinite loop detection is triggered if a cached signal is invalidated by reading it #24409

@Legioth

Description

@Legioth

Description of the bug

I probably triggered this issue as a side effect of #24399 since that issue can lead to a situation where a cached signal detects that the underlying value has changed only when it's being read. I still suspect that the issue can also happen in other edge cases where something else happens that reads the cached signal before the regular cached signal invalidation happens.

java.lang.IllegalStateException: Infinite loop detected between effect updates. This effect is deactivated.
	at com.vaadin.flow.signals.impl.Effect.onDependencyChange(Effect.java:225) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Effect$1.invoke(Effect.java:210) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.CachedSignal$2$1.invoke(CachedSignal.java:179) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.AbstractSharedSignal$1$1.invoke(AbstractSharedSignal.java:506) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.lambda$notifyObservers$1(SignalTree.java:292) ~[flow-server-25.1.5.jar:25.1.5]
	at java.base/java.util.Map.forEach(Map.java:733) ~[na:na]
	at com.vaadin.flow.signals.shared.impl.SignalTree.lambda$notifyObservers$6da5674f$1(SignalTree.java:278) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.runWithLock(SignalTree.java:210) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.notifyObservers(SignalTree.java:277) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SynchronousSignalTree$1.publishChanges(SynchronousSignalTree.java:89) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.lambda$commitSingleCommand$5e536215$1(SignalTree.java:339) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.runWithLock(SignalTree.java:210) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.impl.SignalTree.commitSingleCommand(SignalTree.java:335) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Transaction$ImmediateTransaction.include(Transaction.java:64) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Transaction$RepeatableReadTransaction.include(Transaction.java:110) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Transaction.include(Transaction.java:478) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.AbstractSharedSignal.submit(AbstractSharedSignal.java:324) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.AbstractSharedSignal.submitVoidOperation(AbstractSharedSignal.java:358) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.AbstractSharedSignal.submit(AbstractSharedSignal.java:414) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.CachedSignal.getValidState(CachedSignal.java:222) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.CachedSignal.extractValue(CachedSignal.java:257) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.shared.AbstractSharedSignal.get(AbstractSharedSignal.java:189) ~[flow-server-25.1.5.jar:25.1.5]
	at com.example.demo.MainView.lambda$9(MainView.java:69) ~[classes/:na]
	at com.vaadin.flow.dom.ElementEffect$1.execute(ElementEffect.java:259) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.dom.ElementEffect.executeAction(ElementEffect.java:125) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Effect.lambda$new$ac508a99$1(Effect.java:141) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.UsageTracker.lambda$track$0(UsageTracker.java:221) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.UsageTracker.track(UsageTracker.java:247) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.UsageTracker.track(UsageTracker.java:220) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Effect.revalidate(Effect.java:187) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Effect.invalidate(Effect.java:260) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.signals.impl.Effect.lambda$scheduleInvalidate$2(Effect.java:247) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.component.UI.accessSynchronously(UI.java:504) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.component.UI$2.execute(UI.java:575) ~[flow-server-25.1.5.jar:25.1.5]
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[na:na]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
	at com.vaadin.flow.server.VaadinService.runPendingAccessTasks(VaadinService.java:2340) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.server.VaadinSession.unlock(VaadinSession.java:790) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.server.VaadinService.ensureAccessQueuePurged(VaadinService.java:2304) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.server.VaadinService.accessSession(VaadinService.java:2271) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.server.VaadinSession.access(VaadinSession.java:1095) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.component.UI.access(UI.java:572) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.component.UI.access(UI.java:555) ~[flow-server-25.1.5.jar:25.1.5]
	at com.vaadin.flow.dom.ElementEffect.lambda$enableEffect$0(ElementEffect.java:307) ~[flow-server-25.1.5.jar:25.1.5]

Expected behavior

Effect invocations that are indirectly triggered by an effect reading a cached signal should somehow be ignored for the purpose of detecting infinite loops between effects.

Minimal reproducible example

I do unfortunately not have an easily shared reliable reproduction case

Versions

  • Vaadin / Flow version: Vaadin 25.1.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions