feat: instrument model
This commit is contained in:
@@ -563,3 +563,93 @@ def scrape_upcoming(weeks_ahead: int = 5) -> Dict[str, Any]:
|
||||
conn.close()
|
||||
print(f"[FF scrape] total upserted: {total_inserted}", flush=True)
|
||||
return {"weeks_scraped": weeks_ahead, "total_upserted": total_inserted, "by_week": week_results}
|
||||
|
||||
|
||||
def sync_historical_range(from_date: date, to_date: Optional[date] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Backfill ff_calendar for a historical date range by scraping FF HTML week by week.
|
||||
Skips weeks that already have events with actual_value populated (avoids redundant requests).
|
||||
Adds a small delay between requests to be respectful of the server.
|
||||
Returns progress stats.
|
||||
"""
|
||||
import time
|
||||
from services.database import get_conn
|
||||
|
||||
if to_date is None:
|
||||
to_date = date.today()
|
||||
|
||||
# Align from_date to the Monday of its week
|
||||
monday_start = from_date - timedelta(days=from_date.weekday())
|
||||
monday_today = to_date - timedelta(days=to_date.weekday())
|
||||
|
||||
# Collect all Mondays in range
|
||||
mondays: list[date] = []
|
||||
cur = monday_start
|
||||
while cur <= monday_today:
|
||||
mondays.append(cur)
|
||||
cur += timedelta(weeks=1)
|
||||
|
||||
if not mondays:
|
||||
return {"weeks_scraped": 0, "total_upserted": 0, "skipped": 0, "by_week": {}}
|
||||
|
||||
conn = get_conn()
|
||||
|
||||
# Pre-check which weeks already have actual values to avoid redundant scraping
|
||||
# A week is "done" if it has ≥5 events with actual_value for supported currencies
|
||||
weeks_with_actuals: set[str] = set()
|
||||
for m in mondays:
|
||||
sunday = m + timedelta(days=6)
|
||||
cnt = conn.execute(
|
||||
"""SELECT COUNT(*) FROM ff_calendar
|
||||
WHERE event_date >= ? AND event_date <= ?
|
||||
AND actual_value IS NOT NULL""",
|
||||
(str(m), str(sunday))
|
||||
).fetchone()[0]
|
||||
if cnt >= 5:
|
||||
weeks_with_actuals.add(str(m))
|
||||
|
||||
total_inserted = 0
|
||||
skipped = 0
|
||||
week_results: Dict[str, Any] = {}
|
||||
|
||||
with httpx.Client(headers=_FF_HEADERS, follow_redirects=True, timeout=30) as client:
|
||||
# Warm up session
|
||||
try:
|
||||
client.get(_FF_BASE, timeout=10)
|
||||
time.sleep(1.0)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
for monday in mondays:
|
||||
monday_str = str(monday)
|
||||
if monday_str in weeks_with_actuals:
|
||||
week_results[monday_str] = {"status": "skipped", "count": 0}
|
||||
skipped += 1
|
||||
print(f"[FF backfill] {monday_str}: already populated, skipping", flush=True)
|
||||
continue
|
||||
|
||||
batch = _scrape_week(client, monday)
|
||||
|
||||
if batch:
|
||||
_upsert_batch(conn, batch)
|
||||
conn.commit()
|
||||
total_inserted += len(batch)
|
||||
week_results[monday_str] = {"status": "ok", "count": len(batch)}
|
||||
else:
|
||||
week_results[monday_str] = {"status": "empty", "count": 0}
|
||||
|
||||
print(f"[FF backfill] {monday_str}: {len(batch)} events", flush=True)
|
||||
time.sleep(1.5) # respectful delay between requests
|
||||
|
||||
conn.close()
|
||||
total_weeks = len(mondays)
|
||||
print(f"[FF backfill] done: {total_inserted} events upserted, {skipped}/{total_weeks} weeks skipped", flush=True)
|
||||
return {
|
||||
"from_date": str(from_date),
|
||||
"to_date": str(to_date),
|
||||
"weeks_total": total_weeks,
|
||||
"weeks_scraped": total_weeks - skipped,
|
||||
"weeks_skipped": skipped,
|
||||
"total_upserted": total_inserted,
|
||||
"by_week": week_results,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user