Skip to content

fix(state): persist cancelled redis handler updates - #7412

Open
kr1shna-exe wants to merge 3 commits into
reflex-dev:mainfrom
kr1shna-exe:fix/7248-persist-cancelled-state
Open

kr1shna-exe wants to merge 3 commits into
reflex-dev:mainfrom
kr1shna-exe:fix/7248-persist-cancelled-state

Conversation

@kr1shna-exe

@kr1shna-exe kr1shna-exe commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #7248.

When a foreground handler is cancelled by a superseding event, Redis can discard every state change it made before cancellation, including updates already yielded to the client. The replacement handler then reads the old state. Preserve those changes before releasing the Redis lock so the replacement sees the same history as it does with in-memory state.

What changed

  • Share cancellation-aware persistence across the three non-cached Redis locking paths. Save under the existing lock fence and re-raise cancellation afterward.
  • Cover root and substate writes, handler cleanup, cached leases, expired locks and non-cancellation exceptions.
  • Exercise superseding handlers through the event processor and check both stored state and emitted deltas. Document the behavior and add a news fragment.

Verification

  • Reproduced three failing manager cases and the failing Redis event-processor case before the fix using an isolated Redis server.
  • uv run pytest tests/units --cov --no-cov-on-fail --cov-report=: 11,193 passed, 155 skipped; 78.68% coverage.
  • Redis manager tests against real Redis: 27 passed. Event-processor regression with real Redis and the in-memory control: 2 passed.
  • uv run ruff check ., uv run ruff format --check . and uv run pyright reflex tests passed.
  • All pre-commit hooks applicable to the five changed files passed.
  • All-files pre-commit passed formatting, lint, spelling, stub generation and generated-source checks. Its Pyright hook found six existing macOS CPU-affinity errors in unchanged benchmark files; those files pass with --pythonplatform Linux, matching CI. The remaining ty and Biome hooks passed separately.

Review in cubic

@kr1shna-exe
kr1shna-exe requested review from a team and Alek99 as code owners October 4, 2026 16:46

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 5 files

Re-trigger cubic

@greptile-apps

greptile-apps Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues were found.

Summary

Preserves cancelled foreground handlers’ Redis state before releasing their locks.

  • Redis keeps a cancelled handler’s state for the next event.

The earlier unnumbered thread was manually resolved without explanation. The current shielded save also addresses its concern about a second cancellation interrupting the write.

No new actionable issues were found. Tests were inspected, not run.

Reviews (3) · Last reviewed commit: "Merge main into fix/7248-persist-cancell..." · Reviewed by Greptile

Comment thread reflex/istate/manager/redis.py Outdated
@masenf masenf added bug Something isn't working documentation Improvements or additions to documentation labels Oct 6, 2026
@FarhanAliRaza FarhanAliRaza added the on deck PRs lined up to review / merge next label Oct 22, 2026
@codspeed

codspeed Bot commented Oct 22, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ 19 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 148 untouched benchmarks


Comparing kr1shna-exe:fix/7248-persist-cancelled-state (3f1677e) with main (aeaac72)

Open in CodSpeed


To do so, we can use the Python keyword `yield`. For every yield inside the function, a `StateUpdate` will be sent to the frontend with the changes up to this point in the execution of the event handler.

When using Redis, cancelling a foreground event handler preserves its state changes as long as it still holds the state lock. This includes updates already yielded to the frontend before another invocation of an `@rx.event(supersedes=True)` handler cancels it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add one sentence here: a write the cancelled handler makes after its last yield (for example in its except asyncio.CancelledError cleanup) is stored, but the frontend receives it only with a later update that touches the same var.

Evidence: the disk and memory managers keep the dirty-var bookkeeping on the live state object, so the replacement handler's next delta carries that write. Redis rebuilds the bookkeeping on unpickle (_init_bookkeeping in __setstate__), so the replacement handler's delta does not include it.

Repro: a @rx.event(supersedes=True) handler sets self.entries before the yield and sets Child.last_cancelled only in its except asyncio.CancelledError block. After the replacement handler completes on Redis, the page shows entries with the cancelled handler's values, but Child.last_cancelled stays empty until a page reload. The same app on the disk state manager shows Child.last_cancelled right away.


Generated by Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation on deck PRs lined up to review / merge next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A cancelled foreground supersedes=True handler loses all of its state writes under StateManagerRedis but keeps them under the in-memory manager

3 participants