Fix runtime logging and frontend app regressions
This commit is contained in:
@@ -15,6 +15,9 @@ from backend.data.provider_utils import normalize_symbol
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_SUPPRESSED_LOG_EVERY = 20
|
||||
|
||||
|
||||
class PollingPriceManager:
|
||||
"""Polling-based price manager using Finnhub or yfinance."""
|
||||
|
||||
@@ -43,6 +46,7 @@ class PollingPriceManager:
|
||||
self.latest_prices: Dict[str, float] = {}
|
||||
self.open_prices: Dict[str, float] = {}
|
||||
self.price_callbacks: List[Callable] = []
|
||||
self._failure_counts: Dict[str, int] = {}
|
||||
|
||||
self.running = False
|
||||
self._thread: Optional[threading.Thread] = None
|
||||
@@ -77,6 +81,8 @@ class PollingPriceManager:
|
||||
for symbol in self.subscribed_symbols:
|
||||
try:
|
||||
quote_data = self._fetch_quote(symbol)
|
||||
if not isinstance(quote_data, dict):
|
||||
raise ValueError(f"{symbol}: Empty quote payload")
|
||||
|
||||
current_price = quote_data.get("c")
|
||||
open_price = quote_data.get("o")
|
||||
@@ -103,6 +109,13 @@ class PollingPriceManager:
|
||||
)
|
||||
|
||||
self.latest_prices[symbol] = current_price
|
||||
previous_failures = self._failure_counts.pop(symbol, 0)
|
||||
if previous_failures > 0:
|
||||
logger.info(
|
||||
"%s quote polling recovered after %d consecutive failures",
|
||||
symbol,
|
||||
previous_failures,
|
||||
)
|
||||
|
||||
price_data = {
|
||||
"symbol": symbol,
|
||||
@@ -128,7 +141,20 @@ class PollingPriceManager:
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to fetch {symbol} price: {e}")
|
||||
failure_count = self._failure_counts.get(symbol, 0) + 1
|
||||
self._failure_counts[symbol] = failure_count
|
||||
message = f"Failed to fetch {symbol} price: {e}"
|
||||
|
||||
if failure_count == 1:
|
||||
logger.warning(message)
|
||||
elif failure_count % _SUPPRESSED_LOG_EVERY == 0:
|
||||
logger.warning(
|
||||
"%s (repeated %d times; suppressing intermediate failures)",
|
||||
message,
|
||||
failure_count,
|
||||
)
|
||||
else:
|
||||
logger.debug(message)
|
||||
|
||||
def _fetch_quote(self, symbol: str) -> Dict[str, float]:
|
||||
"""Fetch a normalized quote payload from the configured provider."""
|
||||
@@ -136,7 +162,10 @@ class PollingPriceManager:
|
||||
return self._fetch_yfinance_quote(symbol)
|
||||
if not self.finnhub_client:
|
||||
raise ValueError("Finnhub API key required for finnhub polling")
|
||||
return self.finnhub_client.quote(symbol)
|
||||
quote = self.finnhub_client.quote(symbol)
|
||||
if not isinstance(quote, dict):
|
||||
raise ValueError(f"{symbol}: Invalid Finnhub quote payload")
|
||||
return quote
|
||||
|
||||
def _fetch_yfinance_quote(self, symbol: str) -> Dict[str, float]:
|
||||
"""Fetch quote data from yfinance and normalize to Finnhub-like keys."""
|
||||
@@ -162,6 +191,8 @@ class PollingPriceManager:
|
||||
|
||||
if current_price is None:
|
||||
history = ticker.history(period="1d", interval="1m", auto_adjust=False)
|
||||
if history is None:
|
||||
raise ValueError(f"{symbol}: yfinance returned no history frame")
|
||||
if history.empty:
|
||||
raise ValueError(f"{symbol}: No yfinance quote data")
|
||||
latest = history.iloc[-1]
|
||||
|
||||
Reference in New Issue
Block a user