Skip to content

Skip deep type-validation on state var hot paths#6738

Open
Alek99 wants to merge 3 commits into
mainfrom
claude/reflex-perf-optimizations-01l7a3-eng-10093
Open

Skip deep type-validation on state var hot paths#6738
Alek99 wants to merge 3 commits into
mainfrom
claude/reflex-perf-optimizations-01l7a3-eng-10093

Conversation

@Alek99

@Alek99 Alek99 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Linear: ENG-10093

Description

Two hot paths ran _isinstance(value, type, nested=1), which walks every element of list/dict values, only to gate a diagnostic log that never changes behavior:

  • BaseState.__setattr__ validated the full container on every assignment.
  • ComputedVar.__get__ / AsyncComputedVar.__get__ validated the return type on every access, including cache hits.

Changes:

  • Computed var return types are now validated only when the value is actually recomputed (sync and async). Cache hits skip the check entirely.
  • Element-wise validation depth is now 1 in dev and 0 in prod (new cached _validation_depth() helper in reflex_base.utils.types), so production only checks the outer type. Dev keeps the exact same diagnostics as before.

Benchmarks (GitHub Actions runner, run, 2 passes each)

Case main this PR speedup
read cached computed var returning 10k dicts (dev) 13.81 / 14.05 ms 0.0015 / 0.0015 ms ~9,200x
read cached computed var (prod) 13.66 / 13.93 ms 0.0013 / 0.0015 ms ~9,300x
assign 100k-int list (prod) 90.89 / 90.96 ms 0.020 / 0.024 ms ~4,000x
assign 100k-int list (dev) 90.74 / 92.67 ms 91.76 / 94.74 ms unchanged (by design)

cProfile (3 assigns + 20 cached reads, dev): main spends 3.06s in 10.5M calls dominated by _isinstance (510k calls); with this PR the cached-read side disappears (_check_deprecated_return_type no longer on the cache-hit path) and in prod the whole workload is 538 function calls / 0.003s.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
    • tests/units/reflex_base/vars/test_base.py: return type checked on recompute, not on cache hits (sync, async, and cache=False).
    • tests/units/reflex_base/utils/test_types.py: _validation_depth() is 0 in prod / 1 in dev.
    • tests/units/test_state.py: wrong-typed assignment still logs an error in dev.
  • Have you successfully ran tests with your changes locally?

Note: behavior-wise, a wrong-typed computed var now logs once per recompute instead of once per access, and prod no longer walks container elements for the log-only check. No exceptions or control flow depend on these checks.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X


Generated by Claude Code

Assigning a state var and reading a computed var both ran
_isinstance(value, type, nested=1), walking every element of
list/dict values only to gate a diagnostic log. The computed var
check also ran on every access, including cache hits.

- Validate computed var return types only when the value is
  recomputed (sync and async), not on cache hits.
- Validate one container level deep only in dev mode; production
  now checks just the outer type (the check never gates behavior,
  it only logs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X
@Alek99 Alek99 requested a review from a team as a code owner July 10, 2026 19:53
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

ENG-10093

@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR reduces type-validation work on state hot paths. The main changes are:

  • Adds a validation-depth helper based on REFLEX_ENV_MODE.
  • Uses shallow container checks in production diagnostics.
  • Validates computed-var return types on recompute instead of cache hits.
  • Adds unit coverage for mode changes, assignments, and computed vars.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.
  • The environment mode change now flows through os.environ values that match the validation helper.
  • The new imports add symbols from modules that were already imported on these paths.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/utils/types.py Adds env-aware validation-depth helpers that re-read REFLEX_ENV_MODE on each call.
packages/reflex-base/src/reflex_base/vars/base.py Moves computed-var return validation to recompute paths and uses the new validation depth.
reflex/state.py Uses the new validation depth for state assignment diagnostics.
tests/units/reflex_base/utils/test_types.py Covers production-to-development validation-depth changes without manual cache clearing.
tests/units/reflex_base/vars/test_base.py Covers sync, async, cached, and non-cached computed-var validation behavior.
tests/units/test_state.py Covers wrong-typed state assignment diagnostics.

Reviews (3): Last reviewed commit: "Honor runtime env mode changes in _valid..." | Re-trigger Greptile

Comment thread packages/reflex-base/src/reflex_base/utils/types.py
@codspeed-hq

codspeed-hq Bot commented Jul 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing claude/reflex-perf-optimizations-01l7a3-eng-10093 (f75dcde) with main (9a5c4d3)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X
Comment thread packages/reflex-base/src/reflex_base/utils/types.py
Address review feedback: instead of caching the first observed mode
forever, re-read the raw REFLEX_ENV_MODE value on every call and cache
the depth per raw value, so in-process mode changes take effect
immediately at negligible hot-path cost.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G8cXh3TUbNtbjm2ERqE62X
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants