58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
|
|
"""Daily market-trend aggregator Celery task.
|
||
|
|
|
||
|
|
Fires daily at 04:00 UTC — one hour after the 03:00 RENT scrape so the
|
||
|
|
data is fresh. Calls into `services.market_aggregator` to:
|
||
|
|
1. Recompute per-listing `price_14d_ago` / `price_change_pct_14d`.
|
||
|
|
2. Upsert the per-(listing_type, bedroom-band) row in
|
||
|
|
`dailylistingaggregate` for today's snapshot.
|
||
|
|
|
||
|
|
Idempotent: re-running on the same day refreshes both surfaces in place.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import logging
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
from celery_app import app
|
||
|
|
from database import engine
|
||
|
|
from services import market_aggregator
|
||
|
|
|
||
|
|
celery_logger = logging.getLogger("celery_app")
|
||
|
|
|
||
|
|
|
||
|
|
@app.task(
|
||
|
|
bind=True,
|
||
|
|
name="tasks.market_tasks.compute_daily_market_aggregates_task",
|
||
|
|
time_limit=3600,
|
||
|
|
soft_time_limit=3500,
|
||
|
|
acks_late=True,
|
||
|
|
)
|
||
|
|
def compute_daily_market_aggregates_task(self: Any) -> dict[str, Any]:
|
||
|
|
"""Run both stages of the daily market aggregator."""
|
||
|
|
celery_logger.info("Starting daily market aggregator (task=%s)", self.request.id)
|
||
|
|
per_listing = market_aggregator.update_per_listing_trend(engine)
|
||
|
|
aggregates = market_aggregator.compute_aggregate_snapshot(engine)
|
||
|
|
result = {
|
||
|
|
"status": "ok",
|
||
|
|
"per_listing": per_listing,
|
||
|
|
"aggregates": [
|
||
|
|
{
|
||
|
|
"snapshot_date": a.snapshot_date.isoformat(),
|
||
|
|
"listing_type": a.listing_type,
|
||
|
|
"min_bedrooms": a.min_bedrooms,
|
||
|
|
"max_bedrooms": a.max_bedrooms,
|
||
|
|
"listing_count": a.listing_count,
|
||
|
|
"median_total_price": a.median_total_price,
|
||
|
|
"median_qmprice": a.median_qmprice,
|
||
|
|
}
|
||
|
|
for a in aggregates
|
||
|
|
],
|
||
|
|
}
|
||
|
|
celery_logger.info(
|
||
|
|
"Daily market aggregator complete: rent_updated=%s buy_updated=%s aggregates=%s",
|
||
|
|
per_listing.get("rent_updated"),
|
||
|
|
per_listing.get("buy_updated"),
|
||
|
|
len(aggregates),
|
||
|
|
)
|
||
|
|
return result
|