Skip to content

Commit 81bf3be

Browse files
devin-ai-integration[bot]Alek99masenf
authored
Add documentation for run_in_thread timeout parameter (#1330)
* Add documentation for run_in_thread timeout parameter Co-Authored-By: Alek Petuskey <[email protected]> * Empty whitelist.py as required by CI Co-Authored-By: Alek Petuskey <[email protected]> * Trigger CI to check empty whitelist Co-Authored-By: Alek Petuskey <[email protected]> * Apply suggestions from code review * Apply suggestions from code review --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Alek Petuskey <[email protected]> Co-authored-by: Masen Furer <[email protected]>
1 parent 7ff23e3 commit 81bf3be

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

docs/api-reference/utils.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
```python exec
2+
import reflex as rx
3+
from pcweb import constants, styles
4+
```
5+
6+
# Utility Functions
7+
8+
Reflex provides utility functions to help with common tasks in your applications.
9+
10+
## run_in_thread
11+
12+
The `run_in_thread` function allows you to run a non-async function in a separate thread, which is useful for preventing long-running operations from blocking the UI event queue.
13+
14+
```python
15+
async def run_in_thread(func: Callable, *, timeout: float | None = None) -> Any
16+
```
17+
18+
### Parameters
19+
20+
- `func`: The non-async function to run in a separate thread.
21+
- `timeout`: Maximum number of seconds to wait for the function to complete. If `None` (default), wait indefinitely.
22+
23+
### Returns
24+
25+
- The return value of the function.
26+
27+
### Raises
28+
29+
- `ValueError`: If the function is an async function.
30+
- `asyncio.TimeoutError`: If the function execution exceeds the specified timeout.
31+
32+
### Usage
33+
34+
35+
```python demo exec id=run_in_thread_demo
36+
import asyncio
37+
import time
38+
import reflex as rx
39+
40+
41+
class RunInThreadState(rx.State):
42+
result: str = "No result yet"
43+
status: str = "Idle"
44+
45+
@rx.event(background=True)
46+
async def run_quick_task(self):
47+
"""Run a quick task that completes within the timeout."""
48+
async with self:
49+
self.status = "Running quick task..."
50+
51+
def quick_function():
52+
time.sleep(0.5)
53+
return "Quick task completed successfully!"
54+
55+
try:
56+
# Run with a timeout of 2 seconds (more than enough time)
57+
result = await rx.run_in_thread(quick_function, timeout=2.0)
58+
async with self:
59+
self.result = result
60+
self.status = "Idle"
61+
except Exception as e:
62+
async with self:
63+
self.result = f"Error: {str(e)}"
64+
self.status = "Idle"
65+
66+
@rx.event(background=True)
67+
async def run_slow_task(self):
68+
"""Run a slow task that exceeds the timeout."""
69+
async with self:
70+
self.status = "Running slow task..."
71+
72+
def slow_function():
73+
time.sleep(3.0)
74+
return "This should never be returned due to timeout!"
75+
76+
try:
77+
# Run with a timeout of 1 second (not enough time)
78+
result = await rx.run_in_thread(slow_function, timeout=1.0)
79+
async with self:
80+
self.result = result
81+
self.status = "Idle"
82+
except asyncio.TimeoutError:
83+
async with self:
84+
self.result = "Task timed out after 1 second!"
85+
self.status = "Idle"
86+
except Exception as e:
87+
async with self:
88+
self.result = f"Error: {str(e)}"
89+
self.status = "Idle"
90+
91+
92+
def run_in_thread_example():
93+
return rx.vstack(
94+
rx.heading("run_in_thread Example", size="3"),
95+
rx.text("Status: ", RunInThreadState.status),
96+
rx.text("Result: ", RunInThreadState.result),
97+
rx.hstack(
98+
rx.button(
99+
"Run Quick Task (completes within timeout)",
100+
on_click=RunInThreadState.run_quick_task,
101+
color_scheme="green",
102+
),
103+
rx.button(
104+
"Run Slow Task (exceeds timeout)",
105+
on_click=RunInThreadState.run_slow_task,
106+
color_scheme="red",
107+
),
108+
),
109+
width="100%",
110+
align_items="start",
111+
spacing="4",
112+
)
113+
```
114+
115+
### When to Use run_in_thread
116+
117+
Use `run_in_thread` when you need to:
118+
119+
1. Execute CPU-bound operations that would otherwise block the event loop
120+
2. Call synchronous libraries that don't have async equivalents
121+
3. Prevent long-running operations from blocking UI responsiveness
122+
4. Set a maximum execution time for potentially slow operations
123+
124+
### Example: Processing a Large File
125+
126+
```python
127+
import reflex as rx
128+
import time
129+
130+
class FileProcessingState(rx.State):
131+
progress: str = "Ready"
132+
133+
@rx.event(background=True)
134+
async def process_large_file(self):
135+
self.progress = "Processing file..."
136+
137+
def process_file():
138+
# Simulate processing a large file
139+
time.sleep(5)
140+
return "File processed successfully!"
141+
142+
try:
143+
# Set a timeout of 10 seconds
144+
result = await rx.run_in_thread(process_file, timeout=10.0)
145+
async with self:
146+
self.progress = result
147+
except asyncio.TimeoutError:
148+
async with self:
149+
self.progress = "File processing timed out!"
150+
```
151+
152+
### Notes
153+
154+
- The function passed to `run_in_thread` must be a regular (non-async) function.
155+
- Consider setting appropriate timeouts to prevent indefinite blocking.
156+
- Handle `asyncio.TimeoutError` exceptions to gracefully manage timeouts.

pcweb/components/docpage/sidebar/sidebar_items/reference.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def get_sidebar_items_api_reference():
1515
api_reference.special_events,
1616
api_reference.browser_storage,
1717
api_reference.browser_javascript,
18+
api_reference.utils,
1819
],
1920
)
2021
]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""Utils API reference page."""
2+
3+
import reflex as rx
4+
5+
from pcweb.templates.docpage import docpage
6+
7+
8+
@docpage("/docs/api-reference/utils/")
9+
def utils():
10+
"""Utils API reference page."""
11+
with open("docs/api-reference/utils.md", encoding="utf-8") as f:
12+
content = f.read()
13+
return rx.markdown(content)

0 commit comments

Comments
 (0)