@@ -72,16 +72,16 @@ class Live:
7272 compression : Compression or str, default "none"
7373 The compression format for live data. Set to "zstd" for
7474 Zstandard-compressed data from the gateway.
75+ loop : asyncio.AbstractEventLoop, optional
76+ The event loop to run the client connection in. The loop must already be
77+ running on another thread than the caller's. If unspecified, a shared
78+ event loop running on a background thread will be used.
7579
7680 """
7781
78- _loop = asyncio .new_event_loop ()
82+ _shared_loop : asyncio .AbstractEventLoop | None = None
7983 _lock = threading .Lock ()
80- _thread = threading .Thread (
81- target = _loop .run_forever ,
82- name = "databento_live" ,
83- daemon = True ,
84- )
84+ _thread : threading .Thread | None = None
8585
8686 def __init__ (
8787 self ,
@@ -93,6 +93,7 @@ def __init__(
9393 reconnect_policy : ReconnectPolicy | str = ReconnectPolicy .NONE ,
9494 slow_reader_behavior : SlowReaderBehavior | str | None = None ,
9595 compression : Compression = Compression .NONE ,
96+ loop : asyncio .AbstractEventLoop | None = None ,
9697 ) -> None :
9798 if key is None :
9899 key = os .environ .get ("DATABENTO_API_KEY" )
@@ -112,6 +113,7 @@ def __init__(
112113 self ._ts_out = ts_out
113114 self ._compression = compression
114115 self ._heartbeat_interval_s = heartbeat_interval_s
116+ self ._loop = loop if loop is not None else Live ._get_shared_loop ()
115117
116118 self ._metadata : SessionMetadata = SessionMetadata ()
117119 self ._symbology_map : dict [int , str | int ] = {}
@@ -130,9 +132,18 @@ def __init__(
130132
131133 self ._session ._user_callbacks .append (ClientRecordCallback (self ._map_symbol ))
132134
133- with Live ._lock :
134- if not Live ._thread .is_alive ():
135- Live ._thread .start ()
135+ @classmethod
136+ def _get_shared_loop (cls ) -> asyncio .AbstractEventLoop :
137+ with cls ._lock :
138+ if cls ._shared_loop is None :
139+ cls ._shared_loop = asyncio .new_event_loop ()
140+ cls ._thread = threading .Thread (
141+ target = cls ._shared_loop .run_forever ,
142+ name = "databento_live" ,
143+ daemon = True ,
144+ )
145+ cls ._thread .start ()
146+ return cls ._shared_loop
136147
137148 def __del__ (self ) -> None :
138149 try :
@@ -649,7 +660,7 @@ def block_for_close(
649660 try :
650661 asyncio .run_coroutine_threadsafe (
651662 self ._session .wait_for_close (),
652- loop = Live ._loop ,
663+ loop = self ._loop ,
653664 ).result (timeout = timeout )
654665 except (futures .TimeoutError , KeyboardInterrupt ) as exc :
655666 logger .info ("closing session due to %s" , type (exc ).__name__ )
@@ -697,7 +708,7 @@ async def wait_for_close(
697708 waiter = asyncio .wrap_future (
698709 asyncio .run_coroutine_threadsafe (
699710 self ._session .wait_for_close (),
700- loop = Live ._loop ,
711+ loop = self ._loop ,
701712 ),
702713 )
703714
0 commit comments