feat: add backfill API endpoint for historical data collection
All checks were successful
Deploy to Production / deploy (push) Successful in 1m12s
All checks were successful
Deploy to Production / deploy (push) Successful in 1m12s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9b4d678995
commit
98d8c1115e
@ -25,6 +25,7 @@ from app.services.collectors import (
|
||||
ETFCollector,
|
||||
ETFPriceCollector,
|
||||
)
|
||||
from jobs.collection_job import run_backfill
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -71,6 +72,24 @@ def _start_background_collection(collector_cls, **kwargs):
|
||||
thread.start()
|
||||
|
||||
|
||||
def _run_backfill_background(start_year: int):
|
||||
"""Run backfill in a background thread."""
|
||||
try:
|
||||
run_backfill(start_year=start_year)
|
||||
except Exception as e:
|
||||
logger.error("Background backfill failed: %s", e)
|
||||
|
||||
|
||||
def run_backfill_background(start_year: int):
|
||||
"""Start backfill in a daemon thread."""
|
||||
thread = threading.Thread(
|
||||
target=_run_backfill_background,
|
||||
args=(start_year,),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
|
||||
|
||||
@router.post("/collect/stocks", response_model=CollectResponse)
|
||||
async def collect_stocks(
|
||||
current_user: CurrentUser,
|
||||
@ -132,6 +151,16 @@ async def collect_etf_prices(
|
||||
return CollectResponse(message="ETF price collection started")
|
||||
|
||||
|
||||
@router.post("/collect/backfill", response_model=CollectResponse)
|
||||
async def collect_backfill(
|
||||
current_user: CurrentUser,
|
||||
start_year: int = Query(2000, ge=1990, le=2026, description="Start year for backfill"),
|
||||
):
|
||||
"""Backfill historical price data from start_year to today (runs in background)."""
|
||||
run_backfill_background(start_year)
|
||||
return CollectResponse(message=f"Backfill started from {start_year}")
|
||||
|
||||
|
||||
@router.get("/collect/status", response_model=List[JobLogResponse])
|
||||
async def get_collection_status(
|
||||
current_user: CurrentUser,
|
||||
|
||||
@ -157,3 +157,21 @@ def test_scheduler_has_daily_collection_job():
|
||||
trigger = jobs["daily_collection"].trigger
|
||||
trigger_str = str(trigger)
|
||||
assert "18" in trigger_str # hour=18
|
||||
|
||||
|
||||
def test_backfill_api_endpoint(client, admin_auth_headers):
|
||||
"""POST /api/admin/collect/backfill should trigger backfill."""
|
||||
with patch("app.api.admin.run_backfill_background") as mock_backfill:
|
||||
response = client.post(
|
||||
"/api/admin/collect/backfill?start_year=2020",
|
||||
headers=admin_auth_headers,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert "backfill" in response.json()["message"].lower()
|
||||
mock_backfill.assert_called_once()
|
||||
|
||||
|
||||
def test_backfill_api_requires_auth(client):
|
||||
"""POST /api/admin/collect/backfill should require authentication."""
|
||||
response = client.post("/api/admin/collect/backfill")
|
||||
assert response.status_code == 401
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user