|
43 | 43 | from typing_extensions import Self |
44 | 44 |
|
45 | 45 | from reflex import event |
46 | | -from reflex.config import get_config |
| 46 | +from reflex.config import PerformanceMode, get_config |
47 | 47 | from reflex.istate.data import RouterData |
48 | 48 | from reflex.istate.storage import ClientStorageBase |
49 | 49 | from reflex.model import Model |
|
90 | 90 | ReflexRuntimeError, |
91 | 91 | SetUndefinedStateVarError, |
92 | 92 | StateSchemaMismatchError, |
| 93 | + StateTooLargeError, |
93 | 94 | ) |
94 | 95 | from reflex.utils.exec import is_testing_env |
95 | 96 | from reflex.utils.serializers import serializer |
|
110 | 111 | var = computed_var |
111 | 112 |
|
112 | 113 |
|
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() |
117 | 119 |
|
118 | 120 | # Errors caught during pickling of state |
119 | 121 | HANDLED_PICKLE_ERRORS = ( |
@@ -2097,25 +2099,32 @@ def __getstate__(self): |
2097 | 2099 | state["__dict__"].pop(inherited_var_name, None) |
2098 | 2100 | return state |
2099 | 2101 |
|
2100 | | - def _warn_if_too_large( |
| 2102 | + def _check_state_size( |
2101 | 2103 | self, |
2102 | 2104 | pickle_state_size: int, |
2103 | 2105 | ): |
2104 | 2106 | """Print a warning when the state is too large. |
2105 | 2107 |
|
2106 | 2108 | Args: |
2107 | 2109 | pickle_state_size: The size of the pickled state. |
| 2110 | +
|
| 2111 | + Raises: |
| 2112 | + StateTooLargeError: If the state is too large. |
2108 | 2113 | """ |
2109 | 2114 | state_full_name = self.get_full_name() |
2110 | 2115 | if ( |
2111 | 2116 | state_full_name not in _WARNED_ABOUT_STATE_SIZE |
2112 | 2117 | and pickle_state_size > TOO_LARGE_SERIALIZED_STATE |
2113 | 2118 | and self.substates |
2114 | 2119 | ): |
2115 | | - console.warn( |
| 2120 | + msg = ( |
2116 | 2121 | 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." |
2118 | 2123 | ) |
| 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) |
2119 | 2128 | _WARNED_ABOUT_STATE_SIZE.add(state_full_name) |
2120 | 2129 |
|
2121 | 2130 | @classmethod |
@@ -2157,7 +2166,8 @@ def _serialize(self) -> bytes: |
2157 | 2166 | """ |
2158 | 2167 | try: |
2159 | 2168 | 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)) |
2161 | 2171 | return pickle_state |
2162 | 2172 | except HANDLED_PICKLE_ERRORS as og_pickle_error: |
2163 | 2173 | error = ( |
|
0 commit comments