feat(UI): added docker image and config

This commit is contained in:
2025-10-10 11:15:28 +13:00
parent 9e61d18bf6
commit 9f5a25fcf5
23 changed files with 3287 additions and 18 deletions
+148
View File
@@ -0,0 +1,148 @@
"""
Task Queue Manager for sequential execution of scheduled downloads.
Ensures only one task runs at a time.
"""
import asyncio
from typing import Optional, Dict
from datetime import datetime
import logging
logger = logging.getLogger(__name__)
class TaskQueue:
"""
Manages sequential execution of scheduled download tasks.
Ensures only one task runs at a time.
"""
def __init__(self):
self.queue: asyncio.Queue = asyncio.Queue()
self.current_task: Optional[str] = None # Current task_id being executed
self.is_processing: bool = False
self.worker_task: Optional[asyncio.Task] = None
self._execute_callback = None
def set_execute_callback(self, callback):
"""
Set the callback function to execute tasks.
Args:
callback: Async function that takes task_id and executes it
"""
self._execute_callback = callback
async def add_task(self, task_id: str, priority: int = 0):
"""
Add a task to the queue.
Args:
task_id: UUID of the scheduled task
priority: 0 = scheduled (normal), 1 = manual "Run Now" (higher priority)
"""
task_info = {
'task_id': task_id,
'priority': priority,
'queued_at': datetime.now()
}
# For priority tasks, we need to reorder the queue
if priority > 0:
# Get all items from queue
items = []
while not self.queue.empty():
try:
items.append(await asyncio.wait_for(self.queue.get(), timeout=0.1))
except asyncio.TimeoutError:
break
# Add new priority task
await self.queue.put(task_info)
# Re-add other items
for item in items:
await self.queue.put(item)
logger.info(f"Priority task {task_id} added to front of queue (queue_size={self.queue.qsize()})")
else:
await self.queue.put(task_info)
logger.info(f"Task {task_id} added to queue (priority={priority}, queue_size={self.queue.qsize()})")
# Start worker if not already running
if not self.is_processing:
await self.start_worker()
async def start_worker(self):
"""Start the queue worker if not already running"""
if self.worker_task is None or self.worker_task.done():
self.worker_task = asyncio.create_task(self._process_queue())
logger.info("Queue worker started")
async def _process_queue(self):
"""Process tasks from queue sequentially"""
self.is_processing = True
logger.info("Queue worker processing started")
while True:
try:
# Wait for next task (with timeout to allow graceful shutdown)
try:
task_info = await asyncio.wait_for(
self.queue.get(),
timeout=60.0
)
except asyncio.TimeoutError:
# Check if queue is empty
if self.queue.empty():
logger.info("Queue empty, worker stopping")
break
continue
task_id = task_info['task_id']
self.current_task = task_id
logger.info(f"Executing task {task_id} from queue (queue_size={self.queue.qsize()})")
# Execute the task (this will block until download completes)
try:
if self._execute_callback:
await self._execute_callback(task_id)
logger.info(f"Task {task_id} completed successfully")
else:
logger.error(f"No execute callback set, cannot run task {task_id}")
except Exception as e:
logger.error(f"Task {task_id} failed: {e}", exc_info=True)
finally:
self.current_task = None
self.queue.task_done()
except Exception as e:
logger.error(f"Queue worker error: {e}", exc_info=True)
self.is_processing = False
logger.info("Queue worker stopped")
def get_queue_status(self) -> Dict:
"""Get current queue status"""
return {
'current_task': self.current_task,
'queue_size': self.queue.qsize(),
'is_processing': self.is_processing
}
async def stop(self):
"""Stop the queue worker gracefully"""
logger.info("Stopping queue worker...")
if self.worker_task and not self.worker_task.done():
# Wait for current task to complete
try:
await asyncio.wait_for(self.worker_task, timeout=300) # 5 minute timeout
except asyncio.TimeoutError:
logger.warning("Queue worker did not stop within timeout, cancelling")
self.worker_task.cancel()
logger.info("Queue worker stopped")
# Global queue instance
task_queue = TaskQueue()