Skip to content

Commit 5692b27

Browse files
authored
refactor: use run_in_threadpool for asset service calls in watchlist router (ValueCell-ai#220)
## 📝 Pull Request Template ### 1. Related Issue Closes ValueCell-ai#219 ### Type of Change (select one) Performance ### 3. Description Wrapped blocking service calls in the watchlist router with Starlette’s run_in_threadpool to avoid event-loop blocking caused by synchronous underlying libraries (e.g., yfinance). Added the import and updated these async routes: - GET /asset/search - GET /asset/{ticker} - GET /asset/{ticker}/price - GET /{watchlist_name} - GET /asset/{ticker}/price/historical. ### 4. Testing - [x] I have tested this locally. - [x] I have updated or added relevant tests. ### 5. Checklist - [x] I have read the [Code of Conduct](./CODE_OF_CONDUCT.md) - [x] I have followed the [Contributing Guidelines](./CONTRIBUTING.md) - [x] My changes follow the project's coding style
1 parent 424f69b commit 5692b27

1 file changed

Lines changed: 18 additions & 6 deletions

File tree

python/valuecell/server/api/routers/watchlist.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import List, Optional
44

55
from fastapi import APIRouter, HTTPException, Path, Query
6+
from starlette.concurrency import run_in_threadpool
67

78
from ....utils.i18n_utils import parse_and_validate_utc_dates
89
from ...db.repositories.watchlist_repository import get_watchlist_repository
@@ -60,7 +61,8 @@ async def search_assets(
6061
countries_list = countries.split(",") if countries else None
6162

6263
# Perform search using asset service
63-
result = asset_service.search_assets(
64+
result = await run_in_threadpool(
65+
asset_service.search_assets,
6466
query=q,
6567
asset_types=asset_types_list,
6668
exchanges=exchanges_list,
@@ -106,7 +108,9 @@ async def get_asset_detail(
106108
):
107109
"""Get detailed asset information."""
108110
try:
109-
result = asset_service.get_asset_info(ticker, language=language)
111+
result = await run_in_threadpool(
112+
asset_service.get_asset_info, ticker, language=language
113+
)
110114

111115
if not result.get("success", False):
112116
if "not found" in result.get("error", "").lower():
@@ -145,7 +149,9 @@ async def get_asset_price(
145149
):
146150
"""Get current asset price."""
147151
try:
148-
result = asset_service.get_asset_price(ticker, language=language)
152+
result = await run_in_threadpool(
153+
asset_service.get_asset_price, ticker, language=language
154+
)
149155

150156
if not result.get("success", False):
151157
if "not available" in result.get("error", "").lower():
@@ -225,7 +231,8 @@ async def get_watchlist(
225231
"""Get a specific watchlist."""
226232
try:
227233
# Use asset service to get watchlist with prices
228-
result = asset_service.get_watchlist(
234+
result = await run_in_threadpool(
235+
asset_service.get_watchlist,
229236
user_id=DEFAULT_USER_ID,
230237
watchlist_name=watchlist_name,
231238
include_prices=include_prices,
@@ -517,8 +524,13 @@ async def get_asset_historical_prices(
517524
start_dt, end_dt = parse_and_validate_utc_dates(start_date, end_date)
518525

519526
# Get historical price data
520-
result = asset_service.get_historical_prices(
521-
ticker, start_dt, end_dt, interval, language
527+
result = await run_in_threadpool(
528+
asset_service.get_historical_prices,
529+
ticker,
530+
start_dt,
531+
end_dt,
532+
interval,
533+
language,
522534
)
523535

524536
if not result.get("success", False):

0 commit comments

Comments
 (0)