450 lines
12 KiB
Python
450 lines
12 KiB
Python
"""
|
|
Custom exception classes for the ComfyUI Queue Manager.
|
|
Provides structured error handling across all components.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, Optional
|
|
|
|
|
|
class QueueManagerError(Exception):
|
|
"""Base exception class for all queue manager errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
error_code: Optional[str] = None,
|
|
details: Optional[Dict[str, Any]] = None,
|
|
cause: Optional[Exception] = None
|
|
):
|
|
"""Initialize the exception.
|
|
|
|
Args:
|
|
message: Human-readable error message
|
|
error_code: Machine-readable error code
|
|
details: Additional error details
|
|
cause: Original exception that caused this error
|
|
"""
|
|
super().__init__(message)
|
|
self.message = message
|
|
self.error_code = error_code or self.__class__.__name__
|
|
self.details = details or {}
|
|
self.cause = cause
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""Convert the exception to a dictionary for serialization."""
|
|
return {
|
|
"error_type": self.__class__.__name__,
|
|
"error_code": self.error_code,
|
|
"message": self.message,
|
|
"details": self.details,
|
|
"cause": str(self.cause) if self.cause else None
|
|
}
|
|
|
|
|
|
class DatabaseError(QueueManagerError):
|
|
"""Exception raised for database-related errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
operation: Optional[str] = None,
|
|
table: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the database error.
|
|
|
|
Args:
|
|
message: Error message
|
|
operation: Database operation that failed (e.g., 'INSERT', 'UPDATE')
|
|
table: Database table involved in the operation
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if operation:
|
|
details['operation'] = operation
|
|
if table:
|
|
details['table'] = table
|
|
|
|
super().__init__(message, details=details, **kwargs)
|
|
|
|
|
|
class ConnectionError(DatabaseError):
|
|
"""Exception raised for database connection errors."""
|
|
|
|
def __init__(self, message: str, **kwargs):
|
|
super().__init__(
|
|
message,
|
|
error_code="DB_CONNECTION_ERROR",
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class SchemaError(DatabaseError):
|
|
"""Exception raised for database schema-related errors."""
|
|
|
|
def __init__(self, message: str, schema_version: Optional[int] = None, **kwargs):
|
|
details = kwargs.get('details', {})
|
|
if schema_version is not None:
|
|
details['schema_version'] = schema_version
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="DB_SCHEMA_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class ValidationError(QueueManagerError):
|
|
"""Exception raised for data validation errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
field: Optional[str] = None,
|
|
value: Optional[Any] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the validation error.
|
|
|
|
Args:
|
|
message: Error message
|
|
field: Field name that failed validation
|
|
value: Value that failed validation
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if field:
|
|
details['field'] = field
|
|
if value is not None:
|
|
details['value'] = str(value) # Convert to string for serialization
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="VALIDATION_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class QueueServiceError(QueueManagerError):
|
|
"""Exception raised for queue service operations."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
item_id: Optional[str] = None,
|
|
operation: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the queue service error.
|
|
|
|
Args:
|
|
message: Error message
|
|
item_id: Queue item ID involved in the operation
|
|
operation: Queue operation that failed
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if item_id:
|
|
details['item_id'] = item_id
|
|
if operation:
|
|
details['operation'] = operation
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="QUEUE_SERVICE_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class WorkflowExecutionError(QueueManagerError):
|
|
"""Exception raised for workflow execution errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
workflow_id: Optional[str] = None,
|
|
execution_stage: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the workflow execution error.
|
|
|
|
Args:
|
|
message: Error message
|
|
workflow_id: Workflow ID that failed
|
|
execution_stage: Stage of execution where error occurred
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if workflow_id:
|
|
details['workflow_id'] = workflow_id
|
|
if execution_stage:
|
|
details['execution_stage'] = execution_stage
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="WORKFLOW_EXECUTION_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class TimeoutError(QueueManagerError):
|
|
"""Exception raised for timeout-related errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
timeout_seconds: Optional[float] = None,
|
|
operation: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the timeout error.
|
|
|
|
Args:
|
|
message: Error message
|
|
timeout_seconds: Timeout value that was exceeded
|
|
operation: Operation that timed out
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if timeout_seconds is not None:
|
|
details['timeout_seconds'] = timeout_seconds
|
|
if operation:
|
|
details['operation'] = operation
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="TIMEOUT_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class ConfigurationError(QueueManagerError):
|
|
"""Exception raised for configuration-related errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
config_key: Optional[str] = None,
|
|
config_value: Optional[Any] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the configuration error.
|
|
|
|
Args:
|
|
message: Error message
|
|
config_key: Configuration key that caused the error
|
|
config_value: Configuration value that caused the error
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if config_key:
|
|
details['config_key'] = config_key
|
|
if config_value is not None:
|
|
details['config_value'] = str(config_value)
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="CONFIGURATION_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class APIError(QueueManagerError):
|
|
"""Exception raised for API-related errors."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
status_code: int = 500,
|
|
endpoint: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the API error.
|
|
|
|
Args:
|
|
message: Error message
|
|
status_code: HTTP status code
|
|
endpoint: API endpoint that caused the error
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
details['status_code'] = status_code
|
|
if endpoint:
|
|
details['endpoint'] = endpoint
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="API_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class AuthenticationError(APIError):
|
|
"""Exception raised for authentication errors."""
|
|
|
|
def __init__(self, message: str = "Authentication required", **kwargs):
|
|
super().__init__(
|
|
message,
|
|
status_code=401,
|
|
error_code="AUTHENTICATION_ERROR",
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class AuthorizationError(APIError):
|
|
"""Exception raised for authorization errors."""
|
|
|
|
def __init__(self, message: str = "Access denied", **kwargs):
|
|
super().__init__(
|
|
message,
|
|
status_code=403,
|
|
error_code="AUTHORIZATION_ERROR",
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class NotFoundError(APIError):
|
|
"""Exception raised when a resource is not found."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
resource_type: Optional[str] = None,
|
|
resource_id: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the not found error.
|
|
|
|
Args:
|
|
message: Error message
|
|
resource_type: Type of resource that was not found
|
|
resource_id: ID of resource that was not found
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if resource_type:
|
|
details['resource_type'] = resource_type
|
|
if resource_id:
|
|
details['resource_id'] = resource_id
|
|
|
|
super().__init__(
|
|
message,
|
|
status_code=404,
|
|
error_code="NOT_FOUND_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class ConflictError(APIError):
|
|
"""Exception raised for resource conflicts."""
|
|
|
|
def __init__(self, message: str, **kwargs):
|
|
super().__init__(
|
|
message,
|
|
status_code=409,
|
|
error_code="CONFLICT_ERROR",
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class RateLimitError(APIError):
|
|
"""Exception raised when rate limits are exceeded."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str = "Rate limit exceeded",
|
|
retry_after: Optional[int] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the rate limit error.
|
|
|
|
Args:
|
|
message: Error message
|
|
retry_after: Seconds to wait before retrying
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if retry_after is not None:
|
|
details['retry_after'] = retry_after
|
|
|
|
super().__init__(
|
|
message,
|
|
status_code=429,
|
|
error_code="RATE_LIMIT_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class ImportExportError(QueueManagerError):
|
|
"""Exception raised for import/export operations."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
operation: Optional[str] = None,
|
|
file_path: Optional[str] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the import/export error.
|
|
|
|
Args:
|
|
message: Error message
|
|
operation: Operation that failed ('import' or 'export')
|
|
file_path: File path involved in the operation
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if operation:
|
|
details['operation'] = operation
|
|
if file_path:
|
|
details['file_path'] = file_path
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="IMPORT_EXPORT_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
)
|
|
|
|
|
|
class ArchiveError(QueueManagerError):
|
|
"""Exception raised for archive operations."""
|
|
|
|
def __init__(
|
|
self,
|
|
message: str,
|
|
operation: Optional[str] = None,
|
|
item_count: Optional[int] = None,
|
|
**kwargs
|
|
):
|
|
"""Initialize the archive error.
|
|
|
|
Args:
|
|
message: Error message
|
|
operation: Archive operation that failed
|
|
item_count: Number of items involved in the operation
|
|
**kwargs: Additional arguments passed to parent
|
|
"""
|
|
details = kwargs.get('details', {})
|
|
if operation:
|
|
details['operation'] = operation
|
|
if item_count is not None:
|
|
details['item_count'] = item_count
|
|
|
|
super().__init__(
|
|
message,
|
|
error_code="ARCHIVE_ERROR",
|
|
details=details,
|
|
**kwargs
|
|
) |