This commit is contained in:
pacnpal
2024-11-16 22:32:08 +00:00
parent b7d99490cf
commit dac21f2fcd
30 changed files with 5854 additions and 2279 deletions

View File

@@ -0,0 +1,111 @@
"""Process management and cleanup utilities"""
import asyncio
import logging
import subprocess
from typing import Set, Dict, Any
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
logger = logging.getLogger("VideoArchiver")
class ProcessManager:
"""Manages processes and resources for video operations"""
def __init__(self, concurrent_downloads: int = 2):
self._active_processes: Set[subprocess.Popen] = set()
self._processes_lock = asyncio.Lock()
self._shutting_down = False
# Create thread pool with proper naming
self.download_pool = ThreadPoolExecutor(
max_workers=max(1, min(3, concurrent_downloads)),
thread_name_prefix="videoarchiver_download"
)
# Track active downloads
self.active_downloads: Dict[str, Dict[str, Any]] = {}
self._downloads_lock = asyncio.Lock()
async def cleanup(self) -> None:
"""Clean up resources with proper shutdown"""
self._shutting_down = True
try:
# Kill any active processes
async with self._processes_lock:
for process in self._active_processes:
try:
process.terminate()
await asyncio.sleep(0.1) # Give process time to terminate
if process.poll() is None:
process.kill() # Force kill if still running
except Exception as e:
logger.error(f"Error killing process: {e}")
self._active_processes.clear()
# Clean up thread pool
self.download_pool.shutdown(wait=False, cancel_futures=True)
# Clean up active downloads
async with self._downloads_lock:
self.active_downloads.clear()
except Exception as e:
logger.error(f"Error during process manager cleanup: {e}")
finally:
self._shutting_down = False
async def force_cleanup(self) -> None:
"""Force cleanup of all resources"""
try:
# Kill all processes immediately
async with self._processes_lock:
for process in self._active_processes:
try:
process.kill()
except Exception as e:
logger.error(f"Error force killing process: {e}")
self._active_processes.clear()
# Force shutdown thread pool
self.download_pool.shutdown(wait=False, cancel_futures=True)
# Clear all tracking
async with self._downloads_lock:
self.active_downloads.clear()
except Exception as e:
logger.error(f"Error during force cleanup: {e}")
async def track_download(self, url: str, file_path: str) -> None:
"""Track a new download"""
async with self._downloads_lock:
self.active_downloads[url] = {
"file_path": file_path,
"start_time": datetime.utcnow(),
}
async def untrack_download(self, url: str) -> None:
"""Remove download from tracking"""
async with self._downloads_lock:
self.active_downloads.pop(url, None)
async def track_process(self, process: subprocess.Popen) -> None:
"""Track a new process"""
async with self._processes_lock:
self._active_processes.add(process)
async def untrack_process(self, process: subprocess.Popen) -> None:
"""Remove process from tracking"""
async with self._processes_lock:
self._active_processes.discard(process)
@property
def is_shutting_down(self) -> bool:
"""Check if manager is shutting down"""
return self._shutting_down
def get_active_downloads(self) -> Dict[str, Dict[str, Any]]:
"""Get current active downloads"""
return self.acti