fix: trending section blank when scores are stale + trend scorer error isolation

Dashboard _get_trending() was querying scores within 1 day only — if the
nightly trend task hadn't run (e.g. worker restarted mid-run), the trending
section returned empty. Now falls back through 1→3→7→30 day windows so
stale scores always surface something.

Trend scorer now wraps per-bill scoring in try/except so a single bad
newsapi/gnews call can't abort the entire 1600-bill run.

Authored by: Jack Levy
This commit is contained in:
Jack Levy
2026-03-14 19:04:22 -04:00
parent 380ff4addb
commit 41f6f96077
2 changed files with 33 additions and 26 deletions

View File

@@ -16,16 +16,20 @@ router = APIRouter()
async def _get_trending(db: AsyncSession) -> list[dict]: async def _get_trending(db: AsyncSession) -> list[dict]:
# Try progressively wider windows so stale scores still surface results
for days_back in (1, 3, 7, 30):
trending_result = await db.execute( trending_result = await db.execute(
select(Bill) select(Bill)
.options(selectinload(Bill.sponsor), selectinload(Bill.briefs), selectinload(Bill.trend_scores)) .options(selectinload(Bill.sponsor), selectinload(Bill.briefs), selectinload(Bill.trend_scores))
.join(TrendScore, Bill.bill_id == TrendScore.bill_id) .join(TrendScore, Bill.bill_id == TrendScore.bill_id)
.where(TrendScore.score_date >= date.today() - timedelta(days=1)) .where(TrendScore.score_date >= date.today() - timedelta(days=days_back))
.order_by(desc(TrendScore.composite_score)) .order_by(desc(TrendScore.composite_score))
.limit(10) .limit(10)
) )
trending_bills = trending_result.scalars().unique().all() trending_bills = trending_result.scalars().unique().all()
if trending_bills:
return [_serialize_bill(b) for b in trending_bills] return [_serialize_bill(b) for b in trending_bills]
return []
def _serialize_bill(bill: Bill) -> dict: def _serialize_bill(bill: Bill) -> dict:

View File

@@ -91,6 +91,7 @@ def calculate_all_trend_scores(self):
gtrends_scores = trends_service.get_trends_scores_batch(keyword_groups) gtrends_scores = trends_service.get_trends_scores_batch(keyword_groups)
for i, bill in enumerate(batch): for i, bill in enumerate(batch):
try:
query = bill_queries[i] query = bill_queries[i]
# NewsAPI + Google News counts (gnews served from 2-hour cache) # NewsAPI + Google News counts (gnews served from 2-hour cache)
newsapi_articles = news_service.fetch_newsapi_articles(query, days=30) newsapi_articles = news_service.fetch_newsapi_articles(query, days=30)
@@ -109,6 +110,8 @@ def calculate_all_trend_scores(self):
composite_score=composite, composite_score=composite,
)) ))
scored += 1 scored += 1
except Exception as exc:
logger.warning(f"Trend scoring skipped for {bill.bill_id}: {exc}")
db.commit() db.commit()