Description of the bug
When a shared signal is updated concurrently with an ongoing UIDL request, an effect associated with that UI will be run with the repeatable read transaction used for the ongoing request. If the repeatable read transaction contains the old value of the signal, then the effect will use that value instead of the new value and thus fail to update the UI based on the new value.
This can easily happen when the UIDL request triggers a backend change that uses an asynchronous message bus to reflect the change in a signal. If the message bus delivers the update before the UIDL request is completed, then the effect will read the old value and thus not update anything. If the message delivery is instead slightly slower, then the UIDL request is already finished and the repeatable read transaction is discarded. In that case, the effect will read the updated value and push out an UI update.
Expected behavior
I expect that the latest signal value is eventually shown regardless of what else goes on while the signal is updated.
I suspect the best way of doing this is to explicitly clear the automatic repeatable read transaction before running each pending access task.
Minimal reproducible example
@Route
public class MissingUpdate extends VerticalLayout {
public MissingUpdate() {
SharedNumberSignal signal = new SharedNumberSignal();
add(new Span(() -> "Signal value: " + signal.getAsInt()));
add(new Button("Update during round trip", click -> {
// Prime repeatable read transaction
signal.peek();
try {
Thread thread = Thread.startVirtualThread(() -> signal.incrementBy(1));
// Keep request active until signal is updated
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
add(new Button("Update after round trip", click -> {
signal.peek();
UI ui = UI.getCurrent();
Thread.startVirtualThread(() -> {
// Wait until request has been handled
ui.accessSynchronously(() -> {});
signal.incrementBy(1);
});
}));
add(new Button("Read value", click -> {
Notification.show("Value is " + signal.peek().intValue());
}));
}
}
- Open the view (in an application with
@Push enabled)
- Click the "during" button
- Observe that the label is not updated
- Click the "read" button
- Observe that the notification shows the updated value
- Click the "after" button
- Observe that the label is updated
Versions
- Vaadin / Flow version: Vaadin 25.1.5
Description of the bug
When a shared signal is updated concurrently with an ongoing UIDL request, an effect associated with that UI will be run with the repeatable read transaction used for the ongoing request. If the repeatable read transaction contains the old value of the signal, then the effect will use that value instead of the new value and thus fail to update the UI based on the new value.
This can easily happen when the UIDL request triggers a backend change that uses an asynchronous message bus to reflect the change in a signal. If the message bus delivers the update before the UIDL request is completed, then the effect will read the old value and thus not update anything. If the message delivery is instead slightly slower, then the UIDL request is already finished and the repeatable read transaction is discarded. In that case, the effect will read the updated value and push out an UI update.
Expected behavior
I expect that the latest signal value is eventually shown regardless of what else goes on while the signal is updated.
I suspect the best way of doing this is to explicitly clear the automatic repeatable read transaction before running each pending access task.
Minimal reproducible example
@Pushenabled)Versions