fix(vars): use monotonic time for computed var intervals - #6768
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR fixes a correctness bug in cached computed vars where
Confidence Score: 5/5Safe to merge. The change is narrowly scoped to interval expiry logic, is backward-compatible with older workers via the retained wall-clock attribute, and is fully covered by targeted regression tests. The monotonic-clock logic is correct: UUID tagging cleanly isolates per-process readings, the wall-clock fallback handles cross-process and legacy state, and isinstance guards prevent crashes on unexpected attribute types. All affected code paths are exercised by the new tests, which were confirmed to fail against the old implementation. Files Needing Attention: No files require special attention.
|
| Filename | Overview |
|---|---|
| packages/reflex-base/src/reflex_base/vars/base.py | Replaces datetime.now() with time.monotonic() for interval checks; adds UUID-tagged monotonic attribute and wall-clock fallback for cross-process compatibility. Logic is correct and backward-compatible. |
| tests/units/vars/test_base.py | Adds five targeted regression tests covering monotonic expiry, legacy datetime persistence, wall-clock fallback, cross-instance caching, and incompatible timestamp formats. Good coverage of the new code paths. |
| packages/reflex-base/news/6768.bugfix.md | Changelog entry describing the fix accurately. |
Reviews (4): Last reviewed commit: "test(vars): cover cross-instance cache r..." | Re-trigger Greptile
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
9339a6c to
98b18e3
Compare
Store the wall-clock datetime under the legacy last-updated attribute so older workers sharing a Redis state store never see an unreadable tuple, and record the monotonic reading in a separate companion attribute tagged with a per-process clock id. Interval checks use the monotonic reading when it came from this process and fall back to the wall-clock comparison otherwise, instead of forcing a recompute. Also rename the news fragment to match the PR number (6768, not 6740).
Sequential requests landing on different workers must not force recomputation of a fresh interval var; a foreign clock id degrades to the wall-clock comparison, preserving cross-instance caching in Redis.
FarhanAliRaza
left a comment
There was a problem hiding this comment.
This change actually breaks rolling deployment as old worker can still use old datetime based time for computed vars.
Need better solution. Or atleast we know we have considered different solutions.
|
masenf
left a comment
There was a problem hiding this comment.
holding off on this one due to the potential for over-recomputing when a client bounces between different instances. probably we will take it for correctness eventually, it doesn't seem like something that happens a lot in the real world.
Summary
Cached computed vars used
datetime.now()to decide when an update interval hadelapsed. Wall-clock adjustments could therefore refresh a value early or keep it
cached longer than requested.
This change:
time.monotonic()for synchronous andasynchronous computed vars
cross-process persisted timestamps instead of comparing incompatible clocks
incompatible persisted timestamp formats
Because monotonic clocks cannot be compared across processes, an interval-cached
value restored in another worker now recomputes on first access. Subsequent interval
checks use elapsed time within that process.
Testing
uv run pytest tests/units/vars/test_base.py -q(18 passed)uv run pytest tests/units --cov --no-cov-on-fail --cov-report=(6630 passed,17 skipped, 78.07% coverage)
uv run ruff check .uv run ruff format --check .uv run pyright reflex tests(0 errors)uv run towncrier check --config pyproject.toml --dir packages/reflex-base --compare-with origin/mainThe regression tests fail against the previous implementation and pass with this
change.