53 lines
1.4 KiB
Python
53 lines
1.4 KiB
Python
"""Shared asyncio loop lifecycle helpers for the desktop application.
|
|
|
|
The GUI runs on Tk's main thread, while database calls are executed on a
|
|
dedicated background event loop. These helpers expose that loop as a lazy
|
|
singleton so every module can schedule work on the same async runtime.
|
|
"""
|
|
|
|
import asyncio
|
|
import threading
|
|
|
|
|
|
class _LoopHolder:
|
|
"""Store the global loop instance and its worker thread."""
|
|
|
|
def __init__(self):
|
|
self.loop = None
|
|
self.thread = None
|
|
|
|
|
|
_GLOBAL = _LoopHolder()
|
|
|
|
|
|
def get_global_loop() -> asyncio.AbstractEventLoop:
|
|
"""Return the shared background event loop.
|
|
|
|
The loop is created lazily the first time the function is called and kept
|
|
alive for the lifetime of the application.
|
|
"""
|
|
if _GLOBAL.loop:
|
|
return _GLOBAL.loop
|
|
|
|
ready = threading.Event()
|
|
|
|
def _run():
|
|
_GLOBAL.loop = asyncio.new_event_loop()
|
|
asyncio.set_event_loop(_GLOBAL.loop)
|
|
ready.set()
|
|
_GLOBAL.loop.run_forever()
|
|
|
|
_GLOBAL.thread = threading.Thread(target=_run, name="asyncio-bg-loop", daemon=True)
|
|
_GLOBAL.thread.start()
|
|
ready.wait()
|
|
return _GLOBAL.loop
|
|
|
|
|
|
def stop_global_loop():
|
|
"""Stop the shared loop and join the background thread if present."""
|
|
if _GLOBAL.loop and _GLOBAL.loop.is_running():
|
|
_GLOBAL.loop.call_soon_threadsafe(_GLOBAL.loop.stop)
|
|
_GLOBAL.thread.join(timeout=2)
|
|
_GLOBAL.loop = None
|
|
_GLOBAL.thread = None
|