fix: seed admin user on startup and run sync as background task
- Seed/update admin user from ADMIN_USERNAME/ADMIN_PASSWORD settings on startup (admin_users table was empty, login was impossible) - POST /api/admin/sync now returns immediately and runs the equipment sync via BackgroundTasks (full sync took minutes and hit nginx 504) - run_sync accepts optional sync_log_id to reuse a pre-created log entry - Adapt admin router test to background sync behavior
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
"""Admin router: login, sync endpoints, sync log."""
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, Query, status
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Response, Query, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from typing import Any
|
||||
@@ -10,7 +10,9 @@ from app.schemas.auth import LoginRequest, TokenResponse, AdminInfo
|
||||
from app.schemas.sync import SyncStatus, SyncLogEntry, SyncTriggerResponse
|
||||
from app.auth import verify_password, create_access_token, get_current_user
|
||||
from app.services.sync_service import SyncService
|
||||
from app.database import async_session
|
||||
from app.cache import cache
|
||||
from datetime import datetime
|
||||
|
||||
router = APIRouter(prefix="/api/admin", tags=["admin"])
|
||||
|
||||
@@ -54,13 +56,37 @@ async def get_me(user: AdminUser = Depends(get_current_user)) -> Any:
|
||||
|
||||
@router.post("/sync", response_model=SyncTriggerResponse)
|
||||
async def trigger_sync(
|
||||
background_tasks: BackgroundTasks,
|
||||
user: AdminUser = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
) -> Any:
|
||||
"""Trigger a manual equipment sync (admin only)."""
|
||||
sync_service = SyncService(db)
|
||||
result = await sync_service.run_sync()
|
||||
return SyncTriggerResponse(sync_id=result["sync_id"], status=result["status"])
|
||||
"""Trigger a manual equipment sync in the background (admin only).
|
||||
|
||||
Runs the sync via BackgroundTasks so the HTTP request returns immediately
|
||||
(a full sync of 700+ items incl. image downloads takes minutes and
|
||||
would otherwise hit proxy timeouts).
|
||||
Poll GET /api/admin/sync-status for progress.
|
||||
"""
|
||||
log_entry = SyncLog(sync_type="equipment", status="running", started_at=datetime.utcnow())
|
||||
db.add(log_entry)
|
||||
await db.commit()
|
||||
await db.refresh(log_entry)
|
||||
|
||||
async def _run_sync(sync_id: int) -> None:
|
||||
async with async_session() as sync_db:
|
||||
sync_service = SyncService(sync_db)
|
||||
try:
|
||||
await sync_service.run_sync(sync_log_id=sync_id)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
log = await sync_db.get(SyncLog, sync_id)
|
||||
if log:
|
||||
log.status = "failed"
|
||||
log.error_message = str(exc)
|
||||
log.completed_at = datetime.utcnow()
|
||||
await sync_db.commit()
|
||||
|
||||
background_tasks.add_task(_run_sync, log_entry.id)
|
||||
return SyncTriggerResponse(sync_id=log_entry.id, status="running")
|
||||
|
||||
|
||||
@router.get("/sync-status", response_model=SyncStatus)
|
||||
|
||||
Reference in New Issue
Block a user