Coverage for core / event_loop.py: 100.0%
23 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 04:49 +0000
1"""
2Singleton event loop management.
4Replaces repeated `asyncio.new_event_loop()` calls (7+ across codebase)
5with a single reusable event loop.
7Before: Each async call creates a new event loop, causing resource leaks.
8After: One event loop per thread, properly managed.
9"""
11import asyncio
12import threading
13import logging
15logger = logging.getLogger('hevolve_core')
17_thread_loops = threading.local()
20def get_or_create_event_loop() -> asyncio.AbstractEventLoop:
21 """
22 Get or create an event loop for the current thread.
23 Reuses existing loops instead of creating new ones each time.
24 """
25 # Check for thread-local loop first
26 loop = getattr(_thread_loops, 'loop', None)
27 if loop is not None and not loop.is_closed():
28 return loop
30 # Try to get existing loop
31 try:
32 loop = asyncio.get_event_loop()
33 if not loop.is_closed():
34 _thread_loops.loop = loop
35 return loop
36 except RuntimeError:
37 pass
39 # Create new loop for this thread
40 loop = asyncio.new_event_loop()
41 asyncio.set_event_loop(loop)
42 _thread_loops.loop = loop
43 logger.debug(f"Created new event loop for thread {threading.current_thread().name}")
44 return loop
47def run_async(coro):
48 """
49 Run an async coroutine from synchronous code.
50 Uses the singleton event loop for the current thread.
51 """
52 loop = get_or_create_event_loop()
53 return loop.run_until_complete(coro)