Skip to content

Commit c13cec3

Browse files
implement performance mode for existing state size check (#4392)
1 parent b5e4b02 commit c13cec3

File tree

3 files changed

+37
-9
lines changed

3 files changed

+37
-9
lines changed

reflex/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,14 @@ class PathExistsFlag:
454454
ExistingPath = Annotated[Path, PathExistsFlag]
455455

456456

457+
class PerformanceMode(enum.Enum):
458+
"""Performance mode for the app."""
459+
460+
WARN = "warn"
461+
RAISE = "raise"
462+
OFF = "off"
463+
464+
457465
class EnvironmentVariables:
458466
"""Environment variables class to instantiate environment variables."""
459467

@@ -550,6 +558,12 @@ class EnvironmentVariables:
550558
# Whether to check for outdated package versions.
551559
REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True)
552560

561+
# In which performance mode to run the app.
562+
REFLEX_PERF_MODE: EnvVar[Optional[PerformanceMode]] = env_var(PerformanceMode.WARN)
563+
564+
# The maximum size of the reflex state in kilobytes.
565+
REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
566+
553567

554568
environment = EnvironmentVariables()
555569

reflex/state.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from typing_extensions import Self
4444

4545
from reflex import event
46-
from reflex.config import get_config
46+
from reflex.config import PerformanceMode, get_config
4747
from reflex.istate.data import RouterData
4848
from reflex.istate.storage import ClientStorageBase
4949
from reflex.model import Model
@@ -90,6 +90,7 @@
9090
ReflexRuntimeError,
9191
SetUndefinedStateVarError,
9292
StateSchemaMismatchError,
93+
StateTooLargeError,
9394
)
9495
from reflex.utils.exec import is_testing_env
9596
from reflex.utils.serializers import serializer
@@ -110,10 +111,11 @@
110111
var = computed_var
111112

112113

113-
# If the state is this large, it's considered a performance issue.
114-
TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
115-
# Only warn about each state class size once.
116-
_WARNED_ABOUT_STATE_SIZE: Set[str] = set()
114+
if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
115+
# If the state is this large, it's considered a performance issue.
116+
TOO_LARGE_SERIALIZED_STATE = environment.REFLEX_STATE_SIZE_LIMIT.get() * 1024
117+
# Only warn about each state class size once.
118+
_WARNED_ABOUT_STATE_SIZE: Set[str] = set()
117119

118120
# Errors caught during pickling of state
119121
HANDLED_PICKLE_ERRORS = (
@@ -2097,25 +2099,32 @@ def __getstate__(self):
20972099
state["__dict__"].pop(inherited_var_name, None)
20982100
return state
20992101

2100-
def _warn_if_too_large(
2102+
def _check_state_size(
21012103
self,
21022104
pickle_state_size: int,
21032105
):
21042106
"""Print a warning when the state is too large.
21052107
21062108
Args:
21072109
pickle_state_size: The size of the pickled state.
2110+
2111+
Raises:
2112+
StateTooLargeError: If the state is too large.
21082113
"""
21092114
state_full_name = self.get_full_name()
21102115
if (
21112116
state_full_name not in _WARNED_ABOUT_STATE_SIZE
21122117
and pickle_state_size > TOO_LARGE_SERIALIZED_STATE
21132118
and self.substates
21142119
):
2115-
console.warn(
2120+
msg = (
21162121
f"State {state_full_name} serializes to {pickle_state_size} bytes "
2117-
"which may present performance issues. Consider reducing the size of this state."
2122+
+ "which may present performance issues. Consider reducing the size of this state."
21182123
)
2124+
if environment.REFLEX_PERF_MODE.get() == PerformanceMode.WARN:
2125+
console.warn(msg)
2126+
elif environment.REFLEX_PERF_MODE.get() == PerformanceMode.RAISE:
2127+
raise StateTooLargeError(msg)
21192128
_WARNED_ABOUT_STATE_SIZE.add(state_full_name)
21202129

21212130
@classmethod
@@ -2157,7 +2166,8 @@ def _serialize(self) -> bytes:
21572166
"""
21582167
try:
21592168
pickle_state = pickle.dumps((self._to_schema(), self))
2160-
self._warn_if_too_large(len(pickle_state))
2169+
if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
2170+
self._check_state_size(len(pickle_state))
21612171
return pickle_state
21622172
except HANDLED_PICKLE_ERRORS as og_pickle_error:
21632173
error = (

reflex/utils/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ class InvalidPropValueError(ReflexError):
151151
"""Raised when a prop value is invalid."""
152152

153153

154+
class StateTooLargeError(ReflexError):
155+
"""Raised when the state is too large to be serialized."""
156+
157+
154158
class SystemPackageMissingError(ReflexError):
155159
"""Raised when a system package is missing."""
156160

0 commit comments

Comments
 (0)