Implement async series data loading with background processing
- Add loading status fields to AnimeSeries model
- Create BackgroundLoaderService for async task processing
- Update POST /api/anime/add to return 202 Accepted immediately
- Add GET /api/anime/{key}/loading-status endpoint
- Integrate background loader with startup/shutdown lifecycle
- Create database migration script for loading status fields
- Add unit tests for BackgroundLoaderService (10 tests, all passing)
- Update AnimeSeriesService.create() to accept loading status fields
Architecture follows clean separation with no code duplication:
- BackgroundLoader orchestrates, doesn't reimplement
- Reuses existing AnimeService, NFOService, WebSocket patterns
- Database-backed status survives restarts
This commit is contained in:
@@ -27,6 +27,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.server.services.anime_service import AnimeService
|
||||
from src.server.services.background_loader_service import BackgroundLoaderService
|
||||
from src.server.services.download_service import DownloadService
|
||||
|
||||
# Security scheme for JWT authentication
|
||||
@@ -40,6 +41,7 @@ _series_app: Optional[SeriesApp] = None
|
||||
# Global service instances
|
||||
_anime_service: Optional["AnimeService"] = None
|
||||
_download_service: Optional["DownloadService"] = None
|
||||
_background_loader_service: Optional["BackgroundLoaderService"] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -452,3 +454,51 @@ def reset_download_service() -> None:
|
||||
"""Reset global DownloadService instance (for testing/config changes)."""
|
||||
global _download_service
|
||||
_download_service = None
|
||||
|
||||
|
||||
def get_background_loader_service() -> "BackgroundLoaderService":
|
||||
"""
|
||||
Dependency to get BackgroundLoaderService instance.
|
||||
|
||||
Returns:
|
||||
BackgroundLoaderService: The background loader service for async data loading
|
||||
|
||||
Raises:
|
||||
HTTPException: If BackgroundLoaderService initialization fails
|
||||
"""
|
||||
global _background_loader_service
|
||||
|
||||
if _background_loader_service is None:
|
||||
try:
|
||||
from src.server.services.background_loader_service import (
|
||||
BackgroundLoaderService,
|
||||
)
|
||||
from src.server.services.websocket_service import get_websocket_service
|
||||
|
||||
anime_service = get_anime_service()
|
||||
series_app = get_series_app()
|
||||
websocket_service = get_websocket_service()
|
||||
|
||||
_background_loader_service = BackgroundLoaderService(
|
||||
websocket_service=websocket_service,
|
||||
anime_service=anime_service,
|
||||
series_app=series_app
|
||||
)
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=(
|
||||
"Failed to initialize BackgroundLoaderService: "
|
||||
f"{str(e)}"
|
||||
),
|
||||
) from e
|
||||
|
||||
return _background_loader_service
|
||||
|
||||
|
||||
def reset_background_loader_service() -> None:
|
||||
"""Reset global BackgroundLoaderService instance (for testing/config changes)."""
|
||||
global _background_loader_service
|
||||
_background_loader_service = None
|
||||
|
||||
Reference in New Issue
Block a user