"""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