@@ -133,6 +133,15 @@ def _update_subs_gauge():
133133_market_data_last_warn_ts : float = 0.0
134134
135135
136+ def _get_market_data_adapter (app = None ):
137+ """Helper to get adapter from app.state or global fallback."""
138+ if app is not None :
139+ adapter = getattr (app .state , "market_data_adapter" , None )
140+ if adapter is not None :
141+ return adapter
142+ return _market_data_adapter
143+
144+
136145async def market_data_event_consumer ():
137146 """
138147 Lightweight consumer that subscribes to the adapter EventBus and processes
@@ -346,7 +355,7 @@ async def _reconcile_once():
346355 logger .exception ("Bootstrap reconcile failed" )
347356 return {"ok" : False , "error" : "exception" }
348357 # schedule background reconcile loop
349- async def reconcile_loop (interval : int = 30 ):
358+ async def reconcile_loop (app , interval : int = 30 ):
350359 # Reconcile state with missing-counts to avoid flapping unsubscriptions
351360 from src .market_data .reconcile import ReconcileState , reconcile_step
352361 state = ReconcileState ()
@@ -358,6 +367,13 @@ async def reconcile_loop(interval: int = 30):
358367 logger .debug ("failed to set module-level reconcile state" )
359368 while True :
360369 try :
370+ # Get adapter via helper
371+ adapter = _get_market_data_adapter (app )
372+ if adapter is None :
373+ logger .warning ("Reconcile loop: adapter not available, skipping iteration" )
374+ await asyncio .sleep (interval )
375+ continue
376+
361377 # Build desired_refcount from open trades
362378 pm = get_position_manager ()
363379 active = pm .get_active_trades_summary ()
@@ -409,22 +425,22 @@ async def reconcile_loop(interval: int = 30):
409425 # compute actions
410426 try :
411427 missing_threshold = getattr (settings , "MARKET_DATA_RECONCILE_MISSING_THRESHOLD" , 3 )
412- res = reconcile_step (_market_data_adapter , desired_refcount , state , missing_threshold = missing_threshold )
428+ res = reconcile_step (adapter , desired_refcount , state , missing_threshold = missing_threshold )
413429 except Exception :
414430 logger .exception ("Reconcile step failed" )
415431 res = {"to_subscribe" : set (), "to_unsubscribe" : set ()}
416432
417433 # perform subscribe/unsubscribe
418434 for tk in res .get ("to_subscribe" , set ()):
419435 try :
420- await _market_data_adapter .subscribe (tk )
436+ await adapter .subscribe (tk )
421437 logger .info ("Reconcile: requested subscribe %s" , str (tk )[:24 ])
422438 except Exception :
423439 logger .exception ("Reconcile: subscribe failed for %s" , tk )
424440
425441 for tk in res .get ("to_unsubscribe" , set ()):
426442 try :
427- await _market_data_adapter .unsubscribe (tk )
443+ await adapter .unsubscribe (tk )
428444 logger .info ("Reconcile: requested unsubscribe %s" , str (tk )[:24 ])
429445 state .missing_count .pop (tk , None )
430446 except Exception :
@@ -443,8 +459,8 @@ async def reconcile_loop(interval: int = 30):
443459 except Exception :
444460 last_age = None
445461 dropped = 0
446- subs_count = len (getattr (_market_data_adapter , "_subs" , set ())) if _market_data_adapter else 0
447- logger .info ("MarketData reconcile heartbeat: active_subscriptions=%d, last_msg_age_s=%s, ws_connected=%s, dropped_total=%s" , subs_count , str (last_age ), str (bool (getattr (_market_data_adapter , '_started' , False ))), str (dropped ))
462+ subs_count = len (getattr (adapter , "_subs" , set ())) if adapter else 0
463+ logger .info ("MarketData reconcile heartbeat: active_subscriptions=%d, last_msg_age_s=%s, ws_connected=%s, dropped_total=%s" , subs_count , str (last_age ), str (bool (getattr (adapter , '_started' , False ))), str (dropped ))
448464 # message-flow verification: if we have subscriptions but no recent messages, warn once per minute
449465 try :
450466 from src .config .settings import get_settings as _get_settings
@@ -458,16 +474,16 @@ async def reconcile_loop(interval: int = 30):
458474 if subs_count > 0 and (last_age is None ) and (now_ts - float (getattr (globals (), "_market_data_last_warn_ts" , 0.0 )) >= 60.0 ):
459475 example_token = None
460476 try :
461- example_token = next (iter (getattr (_market_data_adapter , "_subs" , set ())), None )
477+ example_token = next (iter (getattr (adapter , "_subs" , set ())), None )
462478 except Exception :
463479 example_token = None
464480 providers = {
465- "ws" : bool (getattr (_market_data_adapter , "provider" , None )),
466- "rtds" : bool (getattr (_market_data_adapter , "rtds_provider" , None )),
481+ "ws" : bool (getattr (adapter , "provider" , None )),
482+ "rtds" : bool (getattr (adapter , "rtds_provider" , None )),
467483 }
468484 logger .warning (
469485 "MarketData warning: no messages received but subscriptions>0; ws_connected=%s subs=%d last_msg_age=%s example_token=%s providers=%s" ,
470- str (bool (getattr (_market_data_adapter , "_started" , False ))),
486+ str (bool (getattr (adapter , "_started" , False ))),
471487 subs_count ,
472488 str (last_age ),
473489 str (example_token ),
@@ -481,7 +497,7 @@ async def reconcile_loop(interval: int = 30):
481497 except Exception :
482498 logger .exception ("Reconcile loop iteration failed" )
483499 await asyncio .sleep (interval )
484- rt = asyncio .create_task (reconcile_loop (interval = getattr (settings , 'MARKET_DATA_RECONCILE_SECONDS' , 30 )))
500+ rt = asyncio .create_task (reconcile_loop (app , interval = getattr (settings , 'MARKET_DATA_RECONCILE_SECONDS' , 30 )))
485501 _market_data_tasks .append (rt )
486502 logger .info ("MarketData reconcile loop scheduled" )
487503 except Exception :
0 commit comments