Skip to content

Commit 83a4e54

Browse files
picklelomasenf
authored andcommitted
Catch more errors in frontend/backend (#3346)
1 parent 69a09f5 commit 83a4e54

File tree

6 files changed

+47
-24
lines changed

6 files changed

+47
-24
lines changed

reflex/app.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,13 +1068,12 @@ async def process(
10681068
client_ip: The client_ip.
10691069
10701070
Raises:
1071-
ReflexError: If a reflex specific error occurs during processing the event.
1071+
Exception: If a reflex specific error occurs during processing the event.
10721072
10731073
Yields:
10741074
The state updates after processing the event.
10751075
"""
10761076
from reflex.utils import telemetry
1077-
from reflex.utils.exceptions import ReflexError
10781077

10791078
try:
10801079
# Add request data to the state.
@@ -1118,8 +1117,8 @@ async def process(
11181117

11191118
# Yield the update.
11201119
yield update
1121-
except ReflexError as ex:
1122-
telemetry.send("error", context="backend", detail=str(ex))
1120+
except Exception as ex:
1121+
telemetry.send_error(ex, context="backend")
11231122
raise
11241123

11251124

reflex/app_module_for_backend.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
from concurrent.futures import ThreadPoolExecutor
55

66
from reflex import constants
7+
from reflex.utils import telemetry
78
from reflex.utils.exec import is_prod_mode
89
from reflex.utils.prerequisites import get_app
910

1011
if "app" != constants.CompileVars.APP:
1112
raise AssertionError("unexpected variable name for 'app'")
1213

14+
telemetry.send("compile")
1315
app_module = get_app(reload=False)
1416
app = getattr(app_module, constants.CompileVars.APP)
1517
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
@@ -29,5 +31,6 @@
2931
del compile_future
3032
del get_app
3133
del is_prod_mode
34+
del telemetry
3235
del constants
3336
del ThreadPoolExecutor

reflex/state.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,6 @@ async def _process_event(
14761476
StateUpdate object
14771477
"""
14781478
from reflex.utils import telemetry
1479-
from reflex.utils.exceptions import ReflexError
14801479

14811480
# Get the function to process the event.
14821481
fn = functools.partial(handler.fn, state)
@@ -1516,8 +1515,7 @@ async def _process_event(
15161515
except Exception as ex:
15171516
error = traceback.format_exc()
15181517
print(error)
1519-
if isinstance(ex, ReflexError):
1520-
telemetry.send("error", context="backend", detail=str(ex))
1518+
telemetry.send_error(ex, context="backend")
15211519
yield state._as_state_update(
15221520
handler,
15231521
window_alert("An error occurred. See logs for details."),

reflex/utils/prerequisites.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,8 @@ def get_app(reload: bool = False) -> ModuleType:
233233
234234
Raises:
235235
RuntimeError: If the app name is not set in the config.
236-
exceptions.ReflexError: Reflex specific errors.
237236
"""
238-
from reflex.utils import exceptions, telemetry
237+
from reflex.utils import telemetry
239238

240239
try:
241240
os.environ[constants.RELOAD_CONFIG] = str(reload)
@@ -259,8 +258,8 @@ def get_app(reload: bool = False) -> ModuleType:
259258
importlib.reload(app)
260259

261260
return app
262-
except exceptions.ReflexError as ex:
263-
telemetry.send("error", context="frontend", detail=str(ex))
261+
except Exception as ex:
262+
telemetry.send_error(ex, context="frontend")
264263
raise
265264

266265

reflex/utils/telemetry.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import asyncio
56
import multiprocessing
67
import platform
78

@@ -157,17 +158,7 @@ def _send_event(event_data: dict) -> bool:
157158
return False
158159

159160

160-
def send(event: str, telemetry_enabled: bool | None = None, **kwargs) -> bool:
161-
"""Send anonymous telemetry for Reflex.
162-
163-
Args:
164-
event: The event name.
165-
telemetry_enabled: Whether to send the telemetry (If None, get from config).
166-
kwargs: Additional data to send with the event.
167-
168-
Returns:
169-
Whether the telemetry was sent successfully.
170-
"""
161+
def _send(event, telemetry_enabled, **kwargs):
171162
from reflex.config import get_config
172163

173164
# Get the telemetry_enabled from the config if it is not specified.
@@ -182,3 +173,36 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs) -> bool:
182173
if not event_data:
183174
return False
184175
return _send_event(event_data)
176+
177+
178+
def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
179+
"""Send anonymous telemetry for Reflex.
180+
181+
Args:
182+
event: The event name.
183+
telemetry_enabled: Whether to send the telemetry (If None, get from config).
184+
kwargs: Additional data to send with the event.
185+
"""
186+
187+
async def async_send(event, telemetry_enabled, **kwargs):
188+
return _send(event, telemetry_enabled, **kwargs)
189+
190+
try:
191+
# Within an event loop context, send the event asynchronously.
192+
asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
193+
except RuntimeError:
194+
# If there is no event loop, send the event synchronously.
195+
_send(event, telemetry_enabled, **kwargs)
196+
197+
198+
def send_error(error: Exception, context: str):
199+
"""Send an error event.
200+
201+
Args:
202+
error: The error to send.
203+
context: The context of the error (e.g. "frontend" or "backend")
204+
205+
Returns:
206+
Whether the telemetry was sent successfully.
207+
"""
208+
return send("error", detail=type(error).__name__, context=context)

tests/test_telemetry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_telemetry():
2929

3030
def test_disable():
3131
"""Test that disabling telemetry works."""
32-
assert not telemetry.send("test", telemetry_enabled=False)
32+
assert not telemetry._send("test", telemetry_enabled=False)
3333

3434

3535
@pytest.mark.parametrize("event", ["init", "reinit", "run-dev", "run-prod", "export"])
@@ -43,7 +43,7 @@ def test_send(mocker, event):
4343
)
4444
mocker.patch("platform.platform", return_value="Mocked Platform")
4545

46-
telemetry.send(event, telemetry_enabled=True)
46+
telemetry._send(event, telemetry_enabled=True)
4747
httpx.post.assert_called_once()
4848
if telemetry.get_os() == "Windows":
4949
open.assert_called_with(".web\\reflex.json", "r")

0 commit comments

Comments
 (0)