122 lines
3.8 KiB
Python
122 lines
3.8 KiB
Python
# Роуты запуска задач синхронизации Encar и просмотра истории sync-runs.
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import select, func
|
|
|
|
from ..deps import get_persistence
|
|
from ...storage.db import PersistenceService
|
|
from ...storage.models import SyncRun
|
|
from ...worker.celery_app import celery_app
|
|
from ...worker.tasks import encar_sync_listing_task, encar_sync_vehicle_task
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class SyncVehicleRequest(BaseModel):
|
|
vehicle_url: str
|
|
lane: str = "encar"
|
|
|
|
|
|
class SyncListingRequest(BaseModel):
|
|
car_type: str = "all" # all, domestic, import
|
|
manufacturer: str | None = None
|
|
year_from: int | None = None
|
|
year_to: int | None = None
|
|
price_max: int | None = None
|
|
lane: str = "encar"
|
|
limit: int | None = None
|
|
|
|
|
|
@router.post("/tasks/sync-vehicle")
|
|
def start_sync_vehicle(body: SyncVehicleRequest):
|
|
"""Синхронизация одного авто Encar."""
|
|
result = encar_sync_vehicle_task.apply_async(
|
|
kwargs={"vehicle_url": body.vehicle_url, "lane": body.lane},
|
|
queue="encar",
|
|
)
|
|
return {
|
|
"task_id": result.id,
|
|
"status": "queued",
|
|
"vehicle_url": body.vehicle_url,
|
|
}
|
|
|
|
|
|
@router.post("/tasks/sync-listing")
|
|
def start_sync_listing(body: SyncListingRequest):
|
|
"""Синхронизация листинга Encar через публичный API."""
|
|
result = encar_sync_listing_task.apply_async(
|
|
kwargs={
|
|
"car_type": body.car_type,
|
|
"manufacturer": body.manufacturer,
|
|
"year_from": body.year_from,
|
|
"year_to": body.year_to,
|
|
"price_max": body.price_max,
|
|
"lane": body.lane,
|
|
"limit": body.limit,
|
|
},
|
|
queue="encar",
|
|
)
|
|
return {
|
|
"task_id": result.id,
|
|
"status": "queued",
|
|
"car_type": body.car_type,
|
|
"manufacturer": body.manufacturer,
|
|
}
|
|
|
|
|
|
@router.get("/tasks/{task_id}")
|
|
def get_task_status(task_id: str):
|
|
"""Статус задачи Celery."""
|
|
result = celery_app.AsyncResult(task_id)
|
|
|
|
payload: dict = {
|
|
"task_id": task_id,
|
|
"state": result.state,
|
|
}
|
|
|
|
if result.successful():
|
|
payload["result"] = result.result
|
|
elif result.failed():
|
|
payload["error"] = str(result.result)
|
|
elif result.info is not None:
|
|
payload["meta"] = result.info
|
|
|
|
return payload
|
|
|
|
|
|
@router.get("/sync-runs")
|
|
def list_sync_runs(
|
|
page: int = Query(1, ge=1),
|
|
per_page: int = Query(20, ge=1, le=100),
|
|
persistence: PersistenceService = Depends(get_persistence),
|
|
):
|
|
"""История запусков синхронизации."""
|
|
with persistence.session_scope() as session:
|
|
total = session.execute(select(func.count(SyncRun.id))).scalar() or 0
|
|
offset = (page - 1) * per_page
|
|
runs = session.execute(
|
|
select(SyncRun).order_by(SyncRun.started_at.desc()).offset(offset).limit(per_page)
|
|
).scalars().all()
|
|
|
|
return {
|
|
"total": total,
|
|
"page": page,
|
|
"per_page": per_page,
|
|
"items": [
|
|
{
|
|
"id": run.id,
|
|
"started_at": run.started_at.isoformat() if run.started_at else None,
|
|
"finished_at": run.finished_at.isoformat() if run.finished_at else None,
|
|
"status": run.status,
|
|
"lane": run.lane,
|
|
"ids_fetched": run.ids_fetched,
|
|
"cars_upserted": run.cars_upserted,
|
|
"cars_failed": run.cars_failed,
|
|
"images_upserted": run.images_upserted,
|
|
"error_summary": run.error_summary,
|
|
}
|
|
for run in runs
|
|
],
|
|
}
|