fix queue error
This commit is contained in:
@@ -120,6 +120,9 @@ class DownloadService:
|
||||
"""Initialize the service by loading queue state from database.
|
||||
|
||||
Should be called after database is initialized during app startup.
|
||||
Note: With the simplified model, status/priority/progress are now
|
||||
managed in-memory only. The database stores the queue items
|
||||
for persistence across restarts.
|
||||
"""
|
||||
if self._db_initialized:
|
||||
return
|
||||
@@ -127,44 +130,22 @@ class DownloadService:
|
||||
try:
|
||||
repository = self._get_repository()
|
||||
|
||||
# Load pending items from database
|
||||
pending_items = await repository.get_pending_items()
|
||||
for item in pending_items:
|
||||
# Reset status if was downloading when saved
|
||||
if item.status == DownloadStatus.DOWNLOADING:
|
||||
item.status = DownloadStatus.PENDING
|
||||
await repository.update_status(
|
||||
item.id, DownloadStatus.PENDING
|
||||
)
|
||||
# Load all items from database - they all start as PENDING
|
||||
# since status is now managed in-memory only
|
||||
all_items = await repository.get_all_items()
|
||||
for item in all_items:
|
||||
# All items from database are treated as pending
|
||||
item.status = DownloadStatus.PENDING
|
||||
self._add_to_pending_queue(item)
|
||||
|
||||
# Load failed items from database
|
||||
failed_items = await repository.get_failed_items()
|
||||
for item in failed_items:
|
||||
if item.retry_count < self._max_retries:
|
||||
item.status = DownloadStatus.PENDING
|
||||
await repository.update_status(
|
||||
item.id, DownloadStatus.PENDING
|
||||
)
|
||||
self._add_to_pending_queue(item)
|
||||
else:
|
||||
self._failed_items.append(item)
|
||||
|
||||
# Load completed items for history
|
||||
completed_items = await repository.get_completed_items(limit=100)
|
||||
for item in completed_items:
|
||||
self._completed_items.append(item)
|
||||
|
||||
self._db_initialized = True
|
||||
|
||||
logger.info(
|
||||
"Queue restored from database",
|
||||
pending_count=len(self._pending_queue),
|
||||
failed_count=len(self._failed_items),
|
||||
completed_count=len(self._completed_items),
|
||||
"Queue restored from database: pending_count=%d",
|
||||
len(self._pending_queue),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Failed to load queue from database", error=str(e))
|
||||
logger.error("Failed to load queue from database: %s", e, exc_info=True)
|
||||
# Continue without persistence - queue will work in memory only
|
||||
self._db_initialized = True
|
||||
|
||||
@@ -181,59 +162,28 @@ class DownloadService:
|
||||
repository = self._get_repository()
|
||||
return await repository.save_item(item)
|
||||
except Exception as e:
|
||||
logger.error("Failed to save item to database", error=str(e))
|
||||
logger.error("Failed to save item to database: %s", e)
|
||||
return item
|
||||
|
||||
async def _update_status_in_database(
|
||||
async def _set_error_in_database(
|
||||
self,
|
||||
item_id: str,
|
||||
status: DownloadStatus,
|
||||
error: Optional[str] = None,
|
||||
error: str,
|
||||
) -> bool:
|
||||
"""Update item status in the database.
|
||||
"""Set error message on an item in the database.
|
||||
|
||||
Args:
|
||||
item_id: Download item ID
|
||||
status: New status
|
||||
error: Optional error message
|
||||
error: Error message
|
||||
|
||||
Returns:
|
||||
True if update succeeded
|
||||
"""
|
||||
try:
|
||||
repository = self._get_repository()
|
||||
return await repository.update_status(item_id, status, error)
|
||||
return await repository.set_error(item_id, error)
|
||||
except Exception as e:
|
||||
logger.error("Failed to update status in database", error=str(e))
|
||||
return False
|
||||
|
||||
async def _update_progress_in_database(
|
||||
self,
|
||||
item_id: str,
|
||||
progress: float,
|
||||
downloaded: int,
|
||||
total: Optional[int],
|
||||
speed: Optional[float],
|
||||
) -> bool:
|
||||
"""Update download progress in the database.
|
||||
|
||||
Args:
|
||||
item_id: Download item ID
|
||||
progress: Progress percentage
|
||||
downloaded: Downloaded bytes
|
||||
total: Total bytes
|
||||
speed: Download speed in bytes/sec
|
||||
|
||||
Returns:
|
||||
True if update succeeded
|
||||
"""
|
||||
try:
|
||||
repository = self._get_repository()
|
||||
return await repository.update_progress(
|
||||
item_id, progress, downloaded, total, speed
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Failed to update progress in database", error=str(e))
|
||||
logger.error("Failed to set error in database: %s", e)
|
||||
return False
|
||||
|
||||
async def _delete_from_database(self, item_id: str) -> bool:
|
||||
@@ -249,7 +199,7 @@ class DownloadService:
|
||||
repository = self._get_repository()
|
||||
return await repository.delete_item(item_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to delete from database", error=str(e))
|
||||
logger.error("Failed to delete from database: %s", e)
|
||||
return False
|
||||
|
||||
async def _init_queue_progress(self) -> None:
|
||||
@@ -271,7 +221,7 @@ class DownloadService:
|
||||
)
|
||||
self._queue_progress_initialized = True
|
||||
except Exception as e:
|
||||
logger.error("Failed to initialize queue progress", error=str(e))
|
||||
logger.error("Failed to initialize queue progress: %s", e)
|
||||
|
||||
def _add_to_pending_queue(
|
||||
self, item: DownloadItem, front: bool = False
|
||||
@@ -396,7 +346,7 @@ class DownloadService:
|
||||
return created_ids
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to add items to queue", error=str(e))
|
||||
logger.error("Failed to add items to queue: %s", e)
|
||||
raise DownloadServiceError(f"Failed to add items: {str(e)}") from e
|
||||
|
||||
async def remove_from_queue(self, item_ids: List[str]) -> List[str]:
|
||||
@@ -423,12 +373,10 @@ class DownloadService:
|
||||
item.completed_at = datetime.now(timezone.utc)
|
||||
self._failed_items.append(item)
|
||||
self._active_download = None
|
||||
# Update status in database
|
||||
await self._update_status_in_database(
|
||||
item_id, DownloadStatus.CANCELLED
|
||||
)
|
||||
# Delete cancelled item from database
|
||||
await self._delete_from_database(item_id)
|
||||
removed_ids.append(item_id)
|
||||
logger.info("Cancelled active download", item_id=item_id)
|
||||
logger.info("Cancelled active download: item_id=%s", item_id)
|
||||
continue
|
||||
|
||||
# Check pending queue - O(1) lookup using helper dict
|
||||
@@ -460,7 +408,7 @@ class DownloadService:
|
||||
return removed_ids
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to remove items", error=str(e))
|
||||
logger.error("Failed to remove items: %s", e)
|
||||
raise DownloadServiceError(
|
||||
f"Failed to remove items: {str(e)}"
|
||||
) from e
|
||||
@@ -514,7 +462,7 @@ class DownloadService:
|
||||
logger.info("Queue reordered", reordered_count=len(item_ids))
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to reorder queue", error=str(e))
|
||||
logger.error("Failed to reorder queue: %s", e)
|
||||
raise DownloadServiceError(
|
||||
f"Failed to reorder queue: {str(e)}"
|
||||
) from e
|
||||
@@ -558,7 +506,7 @@ class DownloadService:
|
||||
return "queue_started"
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to start queue processing", error=str(e))
|
||||
logger.error("Failed to start queue processing: %s", e)
|
||||
raise DownloadServiceError(
|
||||
f"Failed to start queue processing: {str(e)}"
|
||||
) from e
|
||||
@@ -847,15 +795,12 @@ class DownloadService:
|
||||
self._add_to_pending_queue(item)
|
||||
retried_ids.append(item.id)
|
||||
|
||||
# Update status in database
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.PENDING
|
||||
)
|
||||
# Status is now managed in-memory only
|
||||
|
||||
logger.info(
|
||||
"Retrying failed item",
|
||||
item_id=item.id,
|
||||
retry_count=item.retry_count
|
||||
"Retrying failed item: item_id=%s, retry_count=%d",
|
||||
item.id,
|
||||
item.retry_count,
|
||||
)
|
||||
|
||||
if retried_ids:
|
||||
@@ -875,7 +820,7 @@ class DownloadService:
|
||||
return retried_ids
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to retry items", error=str(e))
|
||||
logger.error("Failed to retry items: %s", e)
|
||||
raise DownloadServiceError(
|
||||
f"Failed to retry: {str(e)}"
|
||||
) from e
|
||||
@@ -892,21 +837,17 @@ class DownloadService:
|
||||
logger.info("Skipping download due to shutdown")
|
||||
return
|
||||
|
||||
# Update status in memory and database
|
||||
# Update status in memory (status is now in-memory only)
|
||||
item.status = DownloadStatus.DOWNLOADING
|
||||
item.started_at = datetime.now(timezone.utc)
|
||||
self._active_download = item
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.DOWNLOADING
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Starting download",
|
||||
item_id=item.id,
|
||||
serie_key=item.serie_id,
|
||||
serie_name=item.serie_name,
|
||||
season=item.episode.season,
|
||||
episode=item.episode.episode,
|
||||
"Starting download: item_id=%s, serie_key=%s, S%02dE%02d",
|
||||
item.id,
|
||||
item.serie_id,
|
||||
item.episode.season,
|
||||
item.episode.episode,
|
||||
)
|
||||
|
||||
# Execute download via anime service
|
||||
@@ -941,13 +882,11 @@ class DownloadService:
|
||||
|
||||
self._completed_items.append(item)
|
||||
|
||||
# Update database
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.COMPLETED
|
||||
)
|
||||
# Delete completed item from database (status is in-memory)
|
||||
await self._delete_from_database(item.id)
|
||||
|
||||
logger.info(
|
||||
"Download completed successfully", item_id=item.id
|
||||
"Download completed successfully: item_id=%s", item.id
|
||||
)
|
||||
else:
|
||||
raise AnimeServiceError("Download returned False")
|
||||
@@ -955,20 +894,18 @@ class DownloadService:
|
||||
except asyncio.CancelledError:
|
||||
# Handle task cancellation during shutdown
|
||||
logger.info(
|
||||
"Download cancelled during shutdown",
|
||||
item_id=item.id,
|
||||
"Download cancelled during shutdown: item_id=%s",
|
||||
item.id,
|
||||
)
|
||||
item.status = DownloadStatus.CANCELLED
|
||||
item.completed_at = datetime.now(timezone.utc)
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.CANCELLED
|
||||
)
|
||||
# Delete cancelled item from database
|
||||
await self._delete_from_database(item.id)
|
||||
# Return item to pending queue if not shutting down
|
||||
if not self._is_shutting_down:
|
||||
self._add_to_pending_queue(item, front=True)
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.PENDING
|
||||
)
|
||||
# Re-save to database as pending
|
||||
await self._save_to_database(item)
|
||||
raise # Re-raise to properly cancel the task
|
||||
|
||||
except Exception as e:
|
||||
@@ -978,16 +915,14 @@ class DownloadService:
|
||||
item.error = str(e)
|
||||
self._failed_items.append(item)
|
||||
|
||||
# Update database with error
|
||||
await self._update_status_in_database(
|
||||
item.id, DownloadStatus.FAILED, str(e)
|
||||
)
|
||||
# Set error in database
|
||||
await self._set_error_in_database(item.id, str(e))
|
||||
|
||||
logger.error(
|
||||
"Download failed",
|
||||
item_id=item.id,
|
||||
error=str(e),
|
||||
retry_count=item.retry_count,
|
||||
"Download failed: item_id=%s, error=%s, retry_count=%d",
|
||||
item.id,
|
||||
str(e),
|
||||
item.retry_count,
|
||||
)
|
||||
# Note: Failure is already broadcast by AnimeService
|
||||
# via ProgressService when SeriesApp fires failed event
|
||||
|
||||
Reference in New Issue
Block a user