queue fix

This commit is contained in:
Lukas 2025-11-01 15:43:15 +01:00
parent 3be175522f
commit 3c6d82907d
6 changed files with 175 additions and 1456 deletions

View File

@ -17,7 +17,7 @@
"keep_days": 30 "keep_days": 30
}, },
"other": { "other": {
"master_password_hash": "$pbkdf2-sha256$29000$rvXeu1dKqdXau/f.P0cIAQ$mApPqnzZmUlUFDkuzsxMuVV4V4pMba9IwEJO1XsV1MU", "master_password_hash": "$pbkdf2-sha256$29000$MkbonbMWolTKOUfIOcc4Jw$8Aza9RknTXDSwQ1/mc.EwerqRrZ4Yo6tQlust.Nm/kQ",
"anime_directory": "/home/lukas/Volume/serien/" "anime_directory": "/home/lukas/Volume/serien/"
}, },
"version": "1.0.0" "version": "1.0.0"

File diff suppressed because it is too large Load Diff

View File

@ -105,34 +105,20 @@ For each task completed:
--- ---
# Tasks
## 📋 All Tasks Complete! ✅ ### Prerequisites
All phases of the download queue simplification have been successfully implemented: 1. Server is running: `conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app --host 127.0.0.1 --port 8000 --reload`
2. Password: `Hallo123!`
3. Login via browser at `http://127.0.0.1:8000/login`
- ✅ **Phase 1**: Backend simplification (DownloadService + API endpoints) **Deployment Steps:**
- ✅ **Phase 2**: Frontend simplification (queue.html + queue.js + CSS cleanup)
- ✅ **Phase 3**: Testing (Unit tests + API tests)
- ✅ **Phase 4**: Documentation (features.md + infrastructure.md)
--- 1. Commit all changes to git repository
2. Create deployment tag (e.g., `v1.0.0-queue-simplified`)
### Success Criteria 3. Deploy to production environment
4. Monitor logs for any unexpected behavior
- [x] All 5 requirements from feature list are met 5. Verify production queue functionality
- [x] No auto-processing or background queue processing
- [x] Only one download active at a time
- [x] Manual start required to begin downloads
- [x] Stop prevents new downloads but allows current to complete
- [x] All unit tests passing (≥80% coverage)
- [x] All API tests passing
- [ ] Manual testing checklist 100% complete
- [ ] No browser console errors
- [ ] WebSocket updates working in real-time
- [x] Documentation updated (features.md, infrastructure.md)
- [x] Code follows project coding standards
- [ ] No breaking changes to other features
### Notes ### Notes
@ -142,3 +128,5 @@ All phases of the download queue simplification have been successfully implement
- Good foundation for future enhancements if needed - Good foundation for future enhancements if needed
- No database schema changes required - No database schema changes required
- WebSocket infrastructure remains unchanged - WebSocket infrastructure remains unchanged
# Tasks

View File

@ -43,39 +43,27 @@ async def get_queue_status(
queue_status = await download_service.get_queue_status() queue_status = await download_service.get_queue_status()
queue_stats = await download_service.get_queue_stats() queue_stats = await download_service.get_queue_stats()
# Preserve the legacy response contract expected by the original CLI # Build response with field names expected by frontend
# client and existing integration tests. Those consumers still parse # Frontend expects top-level arrays (active_downloads, pending_queue, etc.)
# the bare dictionaries that the pre-FastAPI implementation emitted, # not nested under a 'status' object
# so we keep the canonical field names (``active``/``pending``/ active_downloads = [
# ``completed``/``failed``) and dump each Pydantic object to plain it.model_dump(mode="json")
# JSON-compatible dicts instead of returning the richer for it in queue_status.active_downloads
# ``QueueStatusResponse`` shape directly. This guarantees both the ]
# CLI and older dashboard widgets do not need schema migrations while pending_queue = [
# the new web UI can continue to evolve independently. it.model_dump(mode="json")
status_payload = { for it in queue_status.pending_queue
"is_running": queue_status.is_running, ]
"is_paused": queue_status.is_paused, completed_downloads = [
"active": [ it.model_dump(mode="json")
it.model_dump(mode="json") for it in queue_status.completed_downloads
for it in queue_status.active_downloads ]
], failed_downloads = [
"pending": [ it.model_dump(mode="json")
it.model_dump(mode="json") for it in queue_status.failed_downloads
for it in queue_status.pending_queue ]
],
"completed": [
it.model_dump(mode="json")
for it in queue_status.completed_downloads
],
"failed": [
it.model_dump(mode="json")
for it in queue_status.failed_downloads
],
}
# Add the derived ``success_rate`` metric so dashboards built against # Calculate success rate
# the previous API continue to function without recalculating it
# client-side.
completed = queue_stats.completed_count completed = queue_stats.completed_count
failed = queue_stats.failed_count failed = queue_stats.failed_count
success_rate = None success_rate = None
@ -87,7 +75,12 @@ async def get_queue_status(
return JSONResponse( return JSONResponse(
content={ content={
"status": status_payload, "is_running": queue_status.is_running,
"is_paused": queue_status.is_paused,
"active_downloads": active_downloads,
"pending_queue": pending_queue,
"completed_downloads": completed_downloads,
"failed_downloads": failed_downloads,
"statistics": stats_payload, "statistics": stats_payload,
} }
) )

View File

@ -111,10 +111,16 @@ async def test_get_queue_status(authenticated_client, mock_download_service):
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()
assert "status" in data # Updated to match new response structure
assert "is_running" in data
assert "is_paused" in data
assert "active_downloads" in data
assert "pending_queue" in data
assert "completed_downloads" in data
assert "failed_downloads" in data
assert "statistics" in data assert "statistics" in data
assert data["status"]["is_running"] is True assert data["is_running"] is True
assert data["status"]["is_paused"] is False assert data["is_paused"] is False
mock_download_service.get_queue_status.assert_called_once() mock_download_service.get_queue_status.assert_called_once()
mock_download_service.get_queue_stats.assert_called_once() mock_download_service.get_queue_stats.assert_called_once()

View File

@ -153,15 +153,14 @@ class TestDownloadFlowEndToEnd:
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()
# Verify status structure # Verify status structure (updated for new response format)
assert "status" in data assert "is_running" in data
assert "is_paused" in data
assert "pending_queue" in data
assert "active_downloads" in data
assert "completed_downloads" in data
assert "failed_downloads" in data
assert "statistics" in data assert "statistics" in data
status = data["status"]
assert "pending" in status
assert "active" in status
assert "completed" in status
assert "failed" in status
async def test_add_with_different_priorities(self, authenticated_client): async def test_add_with_different_priorities(self, authenticated_client):
"""Test adding episodes with different priority levels.""" """Test adding episodes with different priority levels."""
@ -292,11 +291,11 @@ class TestDownloadProgressTracking:
if response.status_code == 200: if response.status_code == 200:
data = response.json() data = response.json()
assert "status" in data # Updated for new response format
assert "active_downloads" in data
# Check that items can have progress # Check that items can have progress
status = data["status"] for item in data.get("active_downloads", []):
for item in status.get("active", []):
if "progress" in item and item["progress"]: if "progress" in item and item["progress"]:
assert "percentage" in item["progress"] assert "percentage" in item["progress"]
assert "current_mb" in item["progress"] assert "current_mb" in item["progress"]
@ -358,13 +357,18 @@ class TestErrorHandlingAndRetries:
if add_response.status_code == 201: if add_response.status_code == 201:
# Get queue status to check retry count # Get queue status to check retry count
status_response = await authenticated_client.get("/api/queue/status") status_response = await authenticated_client.get(
"/api/queue/status"
)
if status_response.status_code == 200: if status_response.status_code == 200:
data = status_response.json() data = status_response.json()
# Verify structure includes retry_count field # Verify structure includes retry_count field
for item_list in [data["status"].get("pending", []), # Updated to match new response structure
data["status"].get("failed", [])]: for item_list in [
data.get("pending_queue", []),
data.get("failed_downloads", [])
]:
for item in item_list: for item in item_list:
assert "retry_count" in item assert "retry_count" in item