mirror of
https://github.com/pacnpal/Pac-cogs.git
synced 2025-12-20 10:51:05 -05:00
loads of import fixes
This commit is contained in:
@@ -7,54 +7,65 @@ from typing import Optional, Dict, Any, Set, List, Callable, TypedDict, ClassVar
|
||||
from enum import Enum, auto
|
||||
from datetime import datetime
|
||||
|
||||
from .core.cleanup import cleanup_resources, force_cleanup_resources
|
||||
from .utils.exceptions import (
|
||||
from ..core.cleanup import cleanup_resources, force_cleanup_resources
|
||||
from ..utils.exceptions import (
|
||||
VideoArchiverError,
|
||||
ErrorContext,
|
||||
ErrorSeverity,
|
||||
ComponentError,
|
||||
CleanupError
|
||||
CleanupError,
|
||||
)
|
||||
|
||||
logger = logging.getLogger("VideoArchiver")
|
||||
|
||||
|
||||
class LifecycleState(Enum):
|
||||
"""Possible states in the cog lifecycle"""
|
||||
|
||||
UNINITIALIZED = auto()
|
||||
INITIALIZING = auto()
|
||||
READY = auto()
|
||||
UNLOADING = auto()
|
||||
ERROR = auto()
|
||||
|
||||
|
||||
class TaskStatus(Enum):
|
||||
"""Task execution status"""
|
||||
|
||||
RUNNING = auto()
|
||||
COMPLETED = auto()
|
||||
CANCELLED = auto()
|
||||
FAILED = auto()
|
||||
|
||||
|
||||
class TaskHistory(TypedDict):
|
||||
"""Type definition for task history entry"""
|
||||
|
||||
start_time: str
|
||||
end_time: Optional[str]
|
||||
status: str
|
||||
error: Optional[str]
|
||||
duration: float
|
||||
|
||||
|
||||
class StateHistory(TypedDict):
|
||||
"""Type definition for state history entry"""
|
||||
|
||||
state: str
|
||||
timestamp: str
|
||||
duration: float
|
||||
details: Optional[Dict[str, Any]]
|
||||
|
||||
|
||||
class LifecycleStatus(TypedDict):
|
||||
"""Type definition for lifecycle status"""
|
||||
|
||||
state: str
|
||||
state_history: List[StateHistory]
|
||||
tasks: Dict[str, Any]
|
||||
health: bool
|
||||
|
||||
|
||||
class TaskManager:
|
||||
"""Manages asyncio tasks"""
|
||||
|
||||
@@ -69,20 +80,20 @@ class TaskManager:
|
||||
name: str,
|
||||
coro: Callable[..., Any],
|
||||
callback: Optional[Callable[[asyncio.Task], None]] = None,
|
||||
timeout: Optional[float] = None
|
||||
timeout: Optional[float] = None,
|
||||
) -> asyncio.Task:
|
||||
"""
|
||||
Create and track a task.
|
||||
|
||||
|
||||
Args:
|
||||
name: Task name
|
||||
coro: Coroutine to run
|
||||
callback: Optional completion callback
|
||||
timeout: Optional timeout in seconds
|
||||
|
||||
|
||||
Returns:
|
||||
Created task
|
||||
|
||||
|
||||
Raises:
|
||||
ComponentError: If task creation fails
|
||||
"""
|
||||
@@ -94,14 +105,16 @@ class TaskManager:
|
||||
end_time=None,
|
||||
status=TaskStatus.RUNNING.name,
|
||||
error=None,
|
||||
duration=0.0
|
||||
duration=0.0,
|
||||
)
|
||||
|
||||
if timeout:
|
||||
asyncio.create_task(self._handle_timeout(name, task, timeout))
|
||||
|
||||
if callback:
|
||||
task.add_done_callback(lambda t: self._handle_completion(name, t, callback))
|
||||
task.add_done_callback(
|
||||
lambda t: self._handle_completion(name, t, callback)
|
||||
)
|
||||
else:
|
||||
task.add_done_callback(lambda t: self._handle_completion(name, t))
|
||||
|
||||
@@ -116,15 +129,12 @@ class TaskManager:
|
||||
"TaskManager",
|
||||
"create_task",
|
||||
{"task_name": name},
|
||||
ErrorSeverity.HIGH
|
||||
)
|
||||
ErrorSeverity.HIGH,
|
||||
),
|
||||
)
|
||||
|
||||
async def _handle_timeout(
|
||||
self,
|
||||
name: str,
|
||||
task: asyncio.Task,
|
||||
timeout: float
|
||||
self, name: str, task: asyncio.Task, timeout: float
|
||||
) -> None:
|
||||
"""Handle task timeout"""
|
||||
try:
|
||||
@@ -134,16 +144,14 @@ class TaskManager:
|
||||
logger.warning(f"Task {name} timed out after {timeout}s")
|
||||
task.cancel()
|
||||
self._update_task_history(
|
||||
name,
|
||||
TaskStatus.FAILED,
|
||||
f"Task timed out after {timeout}s"
|
||||
name, TaskStatus.FAILED, f"Task timed out after {timeout}s"
|
||||
)
|
||||
|
||||
def _handle_completion(
|
||||
self,
|
||||
name: str,
|
||||
task: asyncio.Task,
|
||||
callback: Optional[Callable[[asyncio.Task], None]] = None
|
||||
callback: Optional[Callable[[asyncio.Task], None]] = None,
|
||||
) -> None:
|
||||
"""Handle task completion"""
|
||||
try:
|
||||
@@ -169,26 +177,25 @@ class TaskManager:
|
||||
self._tasks.pop(name, None)
|
||||
|
||||
def _update_task_history(
|
||||
self,
|
||||
name: str,
|
||||
status: TaskStatus,
|
||||
error: Optional[str] = None
|
||||
self, name: str, status: TaskStatus, error: Optional[str] = None
|
||||
) -> None:
|
||||
"""Update task history entry"""
|
||||
if name in self._task_history:
|
||||
end_time = datetime.utcnow()
|
||||
start_time = datetime.fromisoformat(self._task_history[name]["start_time"])
|
||||
self._task_history[name].update({
|
||||
"end_time": end_time.isoformat(),
|
||||
"status": status.name,
|
||||
"error": error,
|
||||
"duration": (end_time - start_time).total_seconds()
|
||||
})
|
||||
self._task_history[name].update(
|
||||
{
|
||||
"end_time": end_time.isoformat(),
|
||||
"status": status.name,
|
||||
"error": error,
|
||||
"duration": (end_time - start_time).total_seconds(),
|
||||
}
|
||||
)
|
||||
|
||||
async def cancel_task(self, name: str) -> None:
|
||||
"""
|
||||
Cancel a specific task.
|
||||
|
||||
|
||||
Args:
|
||||
name: Task name to cancel
|
||||
"""
|
||||
@@ -210,15 +217,16 @@ class TaskManager:
|
||||
def get_task_status(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Get status of all tasks.
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary containing task status information
|
||||
"""
|
||||
return {
|
||||
"active_tasks": list(self._tasks.keys()),
|
||||
"history": self._task_history.copy()
|
||||
"history": self._task_history.copy(),
|
||||
}
|
||||
|
||||
|
||||
class StateTracker:
|
||||
"""Tracks lifecycle state and transitions"""
|
||||
|
||||
@@ -228,13 +236,11 @@ class StateTracker:
|
||||
self._record_state()
|
||||
|
||||
def set_state(
|
||||
self,
|
||||
state: LifecycleState,
|
||||
details: Optional[Dict[str, Any]] = None
|
||||
self, state: LifecycleState, details: Optional[Dict[str, Any]] = None
|
||||
) -> None:
|
||||
"""
|
||||
Set current state.
|
||||
|
||||
|
||||
Args:
|
||||
state: New state
|
||||
details: Optional state transition details
|
||||
@@ -242,10 +248,7 @@ class StateTracker:
|
||||
self.state = state
|
||||
self._record_state(details)
|
||||
|
||||
def _record_state(
|
||||
self,
|
||||
details: Optional[Dict[str, Any]] = None
|
||||
) -> None:
|
||||
def _record_state(self, details: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""Record state transition"""
|
||||
now = datetime.utcnow()
|
||||
duration = 0.0
|
||||
@@ -253,17 +256,20 @@ class StateTracker:
|
||||
last_state = datetime.fromisoformat(self.state_history[-1]["timestamp"])
|
||||
duration = (now - last_state).total_seconds()
|
||||
|
||||
self.state_history.append(StateHistory(
|
||||
state=self.state.name,
|
||||
timestamp=now.isoformat(),
|
||||
duration=duration,
|
||||
details=details
|
||||
))
|
||||
self.state_history.append(
|
||||
StateHistory(
|
||||
state=self.state.name,
|
||||
timestamp=now.isoformat(),
|
||||
duration=duration,
|
||||
details=details,
|
||||
)
|
||||
)
|
||||
|
||||
def get_state_history(self) -> List[StateHistory]:
|
||||
"""Get state transition history"""
|
||||
return self.state_history.copy()
|
||||
|
||||
|
||||
class LifecycleManager:
|
||||
"""Manages the lifecycle of the VideoArchiver cog"""
|
||||
|
||||
@@ -278,12 +284,11 @@ class LifecycleManager:
|
||||
self._cleanup_handlers: Set[Callable] = set()
|
||||
|
||||
def register_cleanup_handler(
|
||||
self,
|
||||
handler: Union[Callable[[], None], Callable[[], Any]]
|
||||
self, handler: Union[Callable[[], None], Callable[[], Any]]
|
||||
) -> None:
|
||||
"""
|
||||
Register a cleanup handler.
|
||||
|
||||
|
||||
Args:
|
||||
handler: Cleanup handler function
|
||||
"""
|
||||
@@ -292,14 +297,14 @@ class LifecycleManager:
|
||||
async def initialize_cog(self) -> None:
|
||||
"""
|
||||
Initialize all components with proper error handling.
|
||||
|
||||
|
||||
Raises:
|
||||
ComponentError: If initialization fails
|
||||
"""
|
||||
try:
|
||||
# Initialize components in sequence
|
||||
await self.cog.component_manager.initialize_components()
|
||||
|
||||
|
||||
# Set ready flag
|
||||
self.cog.ready.set()
|
||||
logger.info("VideoArchiver initialization completed successfully")
|
||||
@@ -311,11 +316,8 @@ class LifecycleManager:
|
||||
raise ComponentError(
|
||||
error,
|
||||
context=ErrorContext(
|
||||
"LifecycleManager",
|
||||
"initialize_cog",
|
||||
None,
|
||||
ErrorSeverity.HIGH
|
||||
)
|
||||
"LifecycleManager", "initialize_cog", None, ErrorSeverity.HIGH
|
||||
),
|
||||
)
|
||||
|
||||
def init_callback(self, task: asyncio.Task) -> None:
|
||||
@@ -326,67 +328,57 @@ class LifecycleManager:
|
||||
self.state_tracker.set_state(LifecycleState.READY)
|
||||
except asyncio.CancelledError:
|
||||
logger.warning("Initialization was cancelled")
|
||||
self.state_tracker.set_state(
|
||||
LifecycleState.ERROR,
|
||||
{"reason": "cancelled"}
|
||||
)
|
||||
self.state_tracker.set_state(LifecycleState.ERROR, {"reason": "cancelled"})
|
||||
asyncio.create_task(cleanup_resources(self.cog))
|
||||
except Exception as e:
|
||||
logger.error(f"Initialization failed: {str(e)}", exc_info=True)
|
||||
self.state_tracker.set_state(
|
||||
LifecycleState.ERROR,
|
||||
{"error": str(e)}
|
||||
)
|
||||
self.state_tracker.set_state(LifecycleState.ERROR, {"error": str(e)})
|
||||
asyncio.create_task(cleanup_resources(self.cog))
|
||||
|
||||
async def handle_load(self) -> None:
|
||||
"""
|
||||
Handle cog loading without blocking.
|
||||
|
||||
|
||||
Raises:
|
||||
VideoArchiverError: If load fails
|
||||
"""
|
||||
try:
|
||||
self.state_tracker.set_state(LifecycleState.INITIALIZING)
|
||||
|
||||
|
||||
# Start initialization as background task
|
||||
await self.task_manager.create_task(
|
||||
"initialization",
|
||||
self.initialize_cog(),
|
||||
self.init_callback,
|
||||
timeout=self.INIT_TIMEOUT
|
||||
timeout=self.INIT_TIMEOUT,
|
||||
)
|
||||
logger.info("Initialization started in background")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.state_tracker.set_state(LifecycleState.ERROR)
|
||||
# Ensure cleanup on any error
|
||||
try:
|
||||
await asyncio.wait_for(
|
||||
force_cleanup_resources(self.cog),
|
||||
timeout=self.CLEANUP_TIMEOUT
|
||||
force_cleanup_resources(self.cog), timeout=self.CLEANUP_TIMEOUT
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
logger.error("Force cleanup during load error timed out")
|
||||
raise VideoArchiverError(
|
||||
f"Error during cog load: {str(e)}",
|
||||
context=ErrorContext(
|
||||
"LifecycleManager",
|
||||
"handle_load",
|
||||
None,
|
||||
ErrorSeverity.HIGH
|
||||
)
|
||||
"LifecycleManager", "handle_load", None, ErrorSeverity.HIGH
|
||||
),
|
||||
)
|
||||
|
||||
async def handle_unload(self) -> None:
|
||||
"""
|
||||
Clean up when cog is unloaded.
|
||||
|
||||
|
||||
Raises:
|
||||
CleanupError: If cleanup fails
|
||||
"""
|
||||
self.state_tracker.set_state(LifecycleState.UNLOADING)
|
||||
|
||||
|
||||
try:
|
||||
# Cancel all tasks
|
||||
await self.task_manager.cancel_all_tasks()
|
||||
@@ -397,13 +389,11 @@ class LifecycleManager:
|
||||
# Try normal cleanup
|
||||
try:
|
||||
cleanup_task = await self.task_manager.create_task(
|
||||
"cleanup",
|
||||
cleanup_resources(self.cog),
|
||||
timeout=self.UNLOAD_TIMEOUT
|
||||
"cleanup", cleanup_resources(self.cog), timeout=self.UNLOAD_TIMEOUT
|
||||
)
|
||||
await cleanup_task
|
||||
logger.info("Normal cleanup completed")
|
||||
|
||||
|
||||
except (asyncio.TimeoutError, Exception) as e:
|
||||
if isinstance(e, asyncio.TimeoutError):
|
||||
logger.warning("Normal cleanup timed out, forcing cleanup")
|
||||
@@ -413,8 +403,7 @@ class LifecycleManager:
|
||||
# Force cleanup
|
||||
try:
|
||||
await asyncio.wait_for(
|
||||
force_cleanup_resources(self.cog),
|
||||
timeout=self.CLEANUP_TIMEOUT
|
||||
force_cleanup_resources(self.cog), timeout=self.CLEANUP_TIMEOUT
|
||||
)
|
||||
logger.info("Force cleanup completed")
|
||||
except asyncio.TimeoutError:
|
||||
@@ -426,8 +415,8 @@ class LifecycleManager:
|
||||
"LifecycleManager",
|
||||
"handle_unload",
|
||||
None,
|
||||
ErrorSeverity.CRITICAL
|
||||
)
|
||||
ErrorSeverity.CRITICAL,
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
error = f"Error during force cleanup: {str(e)}"
|
||||
@@ -438,25 +427,19 @@ class LifecycleManager:
|
||||
"LifecycleManager",
|
||||
"handle_unload",
|
||||
None,
|
||||
ErrorSeverity.CRITICAL
|
||||
)
|
||||
ErrorSeverity.CRITICAL,
|
||||
),
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
error = f"Error during cog unload: {str(e)}"
|
||||
logger.error(error, exc_info=True)
|
||||
self.state_tracker.set_state(
|
||||
LifecycleState.ERROR,
|
||||
{"error": str(e)}
|
||||
)
|
||||
self.state_tracker.set_state(LifecycleState.ERROR, {"error": str(e)})
|
||||
raise CleanupError(
|
||||
error,
|
||||
context=ErrorContext(
|
||||
"LifecycleManager",
|
||||
"handle_unload",
|
||||
None,
|
||||
ErrorSeverity.CRITICAL
|
||||
)
|
||||
"LifecycleManager", "handle_unload", None, ErrorSeverity.CRITICAL
|
||||
),
|
||||
)
|
||||
finally:
|
||||
# Clear all references
|
||||
@@ -487,7 +470,7 @@ class LifecycleManager:
|
||||
def get_status(self) -> LifecycleStatus:
|
||||
"""
|
||||
Get current lifecycle status.
|
||||
|
||||
|
||||
Returns:
|
||||
Dictionary containing lifecycle status information
|
||||
"""
|
||||
@@ -495,5 +478,5 @@ class LifecycleManager:
|
||||
state=self.state_tracker.state.name,
|
||||
state_history=self.state_tracker.get_state_history(),
|
||||
tasks=self.task_manager.get_task_status(),
|
||||
health=self.state_tracker.state == LifecycleState.READY
|
||||
health=self.state_tracker.state == LifecycleState.READY,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user