-
Notifications
You must be signed in to change notification settings - Fork 598
Description
When a Flet app uses Python's signal module or threading module, it works perfectly with flet run but freezes (hangs indefinitely) at ft.app() call after building with flet build macos/windows/linux.
Environment
Flet version: 0.25.x (tested)
Python version: 3.13
OS: macOS (also likely affects Windows/Linux)
Build command: flet build macos
Steps to Reproduce
❌ Problematic Code (freezes after build):
import sys
import signal
import flet as ft
import threading
Signal handlers
def signal_handler(sig, frame):
print(f"Signal received: {sig}")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
Threading usage
some_thread = threading.Thread(target=some_function, daemon=True)
some_thread.start()
EventBus with threading.Lock
class EventBus:
_lock = threading.Lock()
def emit(self, event):
with self._lock:
# ... event handling
Main app
def main(page: ft.Page):
page.title = "Test App"
page.add(ft.Text("Hello"))
This works with flet run but FREEZES after flet build
ft.app(target=main)
✅ Working Code (asyncio-only, Flet native):
import flet as ft
import asyncio
Use Flet's native async model
def main(page: ft.Page):
page.title = "Test App"
# Use page.run_task for background work
async def background_task():
while True:
await asyncio.sleep(1)
print("Running...")
page.run_task(background_task)
page.add(ft.Text("Hello"))
ft.app(target=main)
Expected Behavior
App should start normally after flet build execution
Both flet run and built executables should behave identically
Actual Behavior
flet run: Works perfectly ✅
After flet build macos: App freezes at ft.app() call, no UI appears, process hangs indefinitely ❌
Root Cause Analysis
Flet uses a single-threaded async event loop model. When signal handlers or threading primitives are used:
They interfere with Flet's event loop in built executables
flet run is more forgiving and handles these conflicts
Built executables are stricter and freeze when detecting thread/signal conflicts
Solution/Workaround
Remove all threading and signals, use Flet's native async patterns:
Remove signal handlers (unnecessary for GUI apps)
Replace threading.Thread → page.run_task(async_function)
Replace threading.Lock → Not needed (single-threaded model)
For blocking I/O → Use asyncio.to_thread(blocking_function)
Example:
❌ BEFORE (freezes after build)
import threading
def load_data():
# blocking operation
data = requests.get(url).json()
return data
thread = threading.Thread(target=load_data)
thread.start()
✅ AFTER (works everywhere)
import asyncio
async def load_data_async():
# Non-blocking with asyncio.to_thread
data = await asyncio.to_thread(
lambda: requests.get(url).json()
)
return data
page.run_task(load_data_async)
Impact
This issue is critical for developers migrating from Qt/threading-based apps to Flet, as they might unknowingly use threading patterns that work in development but fail in production.
Suggestion
Documentation: Add prominent warning about thread/signal incompatibility in build mode
Runtime detection: Warn users during flet run if signal handlers or threading are detected
Better error message: Instead of silent freeze, show error message about incompatible patterns
Related Issues
Possibly related to #4060 (frozen application)
Similar to #5507 (build hangs)