Skip to content

fix: clear repeatable read transaction before running access tasks#24400

Merged
Artur- merged 8 commits into
mainfrom
claude/slack-session-Hh2bd
May 22, 2026
Merged

fix: clear repeatable read transaction before running access tasks#24400
Artur- merged 8 commits into
mainfrom
claude/slack-session-Hh2bd

Conversation

@Artur-
Copy link
Copy Markdown
Member

@Artur- Artur- commented May 21, 2026

Summary

  • Clear the session-scoped transaction before running pending access tasks during session unlock
  • This ensures effects triggered by access tasks see fresh signal values instead of stale cached values from the repeatable read transaction
  • Added a unit test to verify that clearing the transaction fallback allows fresh reads

Details

When a shared signal is updated concurrently with an ongoing UIDL request, effects associated with that UI would run with the repeatable read transaction used for the request. If the transaction cached the old value, effects would miss the update.

The fix moves sessionScopedTransaction = null to execute before runPendingAccessTasks() instead of after, ensuring access tasks read fresh values.

Test plan

  • Existing unit tests pass
  • New clearingFallback_allowsFreshReads test verifies the fix behavior
  • Manual test with the reproduction case from the issue

Fixes #24399

Slack thread: https://vaadin.slack.com/archives/C6RAXJATF/p1779368249043829?thread_ts=1779368185.339629&cid=C6RAXJATF

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR


Generated by Claude Code

Clear the session-scoped transaction before running pending access tasks
during session unlock. This ensures that effects triggered by access tasks
see fresh signal values instead of stale cached values from the repeatable
read transaction.

Previously, the transaction was cleared after running access tasks and
pushing. This caused effects to read from the cached transaction state,
missing concurrent updates that happened during the UIDL request.

Fixes #24399

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
@cla-assistant
Copy link
Copy Markdown

cla-assistant Bot commented May 21, 2026

CLA assistant check
All committers have signed the CLA.

StringNode doesn't have a "text" property - use textValue() directly.

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

Test Results

 1 418 files  ±0   1 418 suites  ±0   1h 21m 16s ⏱️ ±0s
10 001 tests +1   9 932 ✅ +1  69 💤 ±0  0 ❌ ±0 
10 476 runs  +1  10 405 ✅ +1  71 💤 ±0  0 ❌ ±0 

Results for commit c352151. ± Comparison against base commit eef1d26.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Member

@Legioth Legioth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we instead isolate access tasks from each other so that each task can have its own repeatable read transaction? Otherwise, one tasks might poison the repeatable read transaction for a subsequent task.

claude added 3 commits May 21, 2026 13:36
Instead of clearing the transaction once before all access tasks, clear it
before EACH task so that each task gets its own fresh repeatable read
transaction. This prevents one task from poisoning the cached values for
subsequent tasks.

Each access task now:
- Starts with a cleared session-scoped transaction
- Gets a fresh transaction created on-demand when it first reads a signal
- Has repeatable reads within itself
- Is isolated from other tasks' cached values

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
Each access task now runs in its own isolated write-through transaction
that uses ROOT as the outer, ensuring tasks see fresh signal values and
don't share cached values with each other or with the session-scoped
transaction.

This addresses review feedback to properly isolate access tasks rather
than just clearing the session-scoped transaction before each task.

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
…ch task

The isolated transaction wrapper broke effect tracking and CurrentInstance
handling. Reverting to the simpler approach of clearing the session-scoped
transaction before each access task, which allows fresh signal reads
without interfering with other mechanisms.

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
@Legioth Legioth dismissed their stale review May 21, 2026 14:22

New approach seems to make sense but I don't have time to review the test right now. Removing my review so that someone else feels like they could have a look.

Comment thread flow-server/src/test/java/com/vaadin/flow/signals/impl/TransactionTest.java Outdated
…tasks

Addresses review feedback:
- Remove test from TransactionTest that didn't use the pending access queue
- Add test in VaadinServiceTest that verifies clearSessionScopedTransaction
  is called before each pending access task runs

https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
@Legioth
Copy link
Copy Markdown
Member

Legioth commented May 22, 2026

I tested a locally built snapshot in my actual application and seems like it fixes the original issue that I observed.

Comment thread flow-server/src/test/java/com/vaadin/flow/server/VaadinServiceTest.java Outdated
Addresses Legioth's review feedback: the prior test only verified
clearSessionScopedTransaction was invoked, not that the fix actually
solves the original issue. Replace it with a test that reproduces the
issue #24399 scenario end-to-end:

  - Effect on a UI reads a shared signal during initial run, priming
    the session-scoped repeatable-read transaction.
  - Signal is mutated outside the session transaction (via
    runWithoutTransaction), simulating a concurrent write from another
    session or a background message handler.
  - Effect dispatcher routes the re-run through ui.access(), which
    enqueues it in the pending access queue while the session lock is
    held.
  - When pending access tasks run (simulating session unlock at the
    end of the UIDL request), the effect must observe the fresh value.

Without the fix, the effect re-run sees the cached stale value
("initial"). With the fix, it sees the fresh value ("external").
@Artur- Artur- requested a review from Legioth May 22, 2026 11:32
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Member

@Legioth Legioth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Third time is the charm

@Artur- Artur- marked this pull request as ready for review May 22, 2026 14:07
@Artur- Artur- added this pull request to the merge queue May 22, 2026
Merged via the queue into main with commit c697a09 May 22, 2026
34 checks passed
@Artur- Artur- deleted the claude/slack-session-Hh2bd branch May 22, 2026 14:21
vaadin-bot added a commit that referenced this pull request May 22, 2026
…24400) (CP: 25.1) (#24426)

This PR cherry-picks changes from the original PR #24400 to branch 25.1.
---
#### Original PR description
> ## Summary
> 
> - Clear the session-scoped transaction **before** running pending
access tasks during session unlock
> - This ensures effects triggered by access tasks see fresh signal
values instead of stale cached values from the repeatable read
transaction
> - Added a unit test to verify that clearing the transaction fallback
allows fresh reads
> 
> ## Details
> 
> When a shared signal is updated concurrently with an ongoing UIDL
request, effects associated with that UI would run with the repeatable
read transaction used for the request. If the transaction cached the old
value, effects would miss the update.
> 
> The fix moves `sessionScopedTransaction = null` to execute before
`runPendingAccessTasks()` instead of after, ensuring access tasks read
fresh values.
> 
> ## Test plan
> 
> - [ ] Existing unit tests pass
> - [ ] New `clearingFallback_allowsFreshReads` test verifies the fix
behavior
> - [ ] Manual test with the reproduction case from the issue
> 
> Fixes #24399
> 
> Slack thread:
https://vaadin.slack.com/archives/C6RAXJATF/p1779368249043829?thread_ts=1779368185.339629&cid=C6RAXJATF
> 
> https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR
> 
> ---
> _Generated by [Claude
Code](https://claude.ai/code/session_01QW3F8K4uxGyaUNa9xwoKTR)_

Co-authored-by: Artur Signell <artur@vaadin.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Repeatable read transaction prevents concurrent update from being applied

4 participants