Repository navigation
Fix stale substates after background task state expiry - #7543
harsh21234i wants to merge 37 commits into
Conversation
Merging this PR will degrade performance by 1.75%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | test_modify_state[redis] |
73.1 ms | 82.3 ms | -11.2% |
| ❌ | test_get_state[redis] |
30.6 ms | 32.8 ms | -6.5% |
| ⚡ | test_set_state[redis] |
34.5 ms | 30.2 ms | +14.24% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing harsh21234i:fix/7478-refresh-expired-background-state (3464287) with main (5ae5dcd)
[High impact] Modifies state manager persistence and expiration logic across multiple backends. The Redis manifest must survive state expiry before this is safe to merge. Findings
SummaryRefreshes recreated states when background tasks resume after expiry.
Reviews (18) · Last reviewed commit: "Merge branch 'main' into fix/7478-refres..." · Reviewed by Greptile |
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 8 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
masenf
left a comment
There was a problem hiding this comment.
otherwise looks legit to me. we track the states that are newly created during StateManager operations, then mark those states and their vars dirty when entering the StateProxy so the next delta includes the defaults from the new states (replacing values on the client that were stale from the expired state)
FarhanAliRaza
left a comment
There was a problem hiding this comment.
I tested this PR in a small app that has a root state, a child state, a sibling state with a computed var that reads the child, a ComponentState, and a dynamic route. I ran the same app on this branch and on main at the same time, with a short token TTL and a background task that sleeps longer than the TTL. I used Playwright to read each value from the page.
With the memory manager, the reported problem is fixed. After the background update, the child, the component and the cross-state computed var reset to their defaults. On main, they stay stale. The next foreground event gives the same values on both builds.
With Redis, I kept the root key alive with root-only events and let the other keys expire. I also ran the existing proxy tests against a live Redis server.
The inline comments show the requested changes.
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
# Conflicts: # .github/workflows/examples.yml
Root the proxy test state at BaseState so recovery does not load unrelated rx.State subclasses collected from other test modules. Reproduced the DynamicState missing-field failure with test_app collected before the fix; the focused reproduction and all 286 proxy/app tests pass afterward.
| if #KEYS > 2 then | ||
| redis.call('PEXPIRE', KEYS[2], tonumber(ARGV[2]) * 1000) |
There was a problem hiding this comment.
Expired child values stay visible
The Redis manifest expires at the same time as the last saved state. When a background task waits longer than token_expiration, both the saved states and their manifest disappear. The next load treats every missing state as never saved and reports no recreation. If the task updates only the parent, the browser keeps showing the child's old values.
Keep recreation history available after the state values expire, and add a test that expires both the states and the manifest.
Summary
When a state tree is recreated after expiry, mark the new states dirty so the next delta sends their default frontend values. Track recreation in the memory, disk, and Redis state managers while leaving states loaded from Redis clean. Avoid retaining tracked state references in the memory manager's long-lived expiration task.
Add regression coverage for delayed background updates after child and component state expiry, disk state recreation, Redis persisted and missing states, and unchanged Redis reloads.
Closes #7478
Validation
uv run pytest tests/units/istate -q --maxfail=5(225 passed)uv run pytest tests/integration/test_memory_state_manager_expiration.py -q(6 passed)