""" Custom exception classes for the Booking Allocation Engine. This module defines the exception hierarchy used throughout the allocation system to distinguish between transient errors (retryable) and permanent errors (non-retryable). """ class AllocationError(Exception): """Base exception for all allocation-related errors.""" def __init__(self, message: str, booking_id: str = None, partner_id: str = None): self.message = message self.booking_id = booking_id self.partner_id = partner_id super().__init__(self.message) class TransientError(AllocationError): """ Transient errors that may succeed on retry. These errors indicate temporary failures such as network issues, database connection problems, or service unavailability. Operations that raise TransientError should be retried with backoff. """ pass class PermanentError(AllocationError): """ Permanent errors that will not succeed on retry. These errors indicate business logic violations, validation failures, or data integrity issues that cannot be resolved by retrying. Operations that raise PermanentError should not be retried. """ pass class DatabaseConnectionError(TransientError): """ Database connection or query execution failure. Raised when PostgreSQL connection fails or times out. Should be retried with exponential backoff. """ def __init__(self, message: str, operation: str = None, booking_id: str = None): self.operation = operation super().__init__(message, booking_id=booking_id) class RedisError(TransientError): """ Redis connection or operation failure. Raised when Redis connection fails or times out. Should trigger fallback to PostgreSQL for data retrieval. """ def __init__(self, message: str, key: str = None, operation: str = None): self.key = key self.operation = operation super().__init__(message) class NoEligiblePartnersError(PermanentError): """ No eligible partners found for booking. Raised when partner filtering returns empty result set. Should set allocation_status to 'failed'. """ pass class BookingAlreadyAssignedError(PermanentError): """ Booking already assigned to a partner. Raised when attempting to create offer for already-assigned booking. Should abort allocation attempt. """ pass class InvalidEventStructureError(PermanentError): """ Event structure validation failed. Raised when required fields are missing or have invalid types. Event should be discarded and logged. """ def __init__(self, message: str, event_data: dict = None): self.event_data = event_data super().__init__(message) class OfferExpiredError(PermanentError): """ Offer has already expired. Raised when partner responds after offer expiry timeout. Response should be rejected. """ def __init__(self, message: str, offer_id: str = None, expiry_time: str = None): self.offer_id = offer_id self.expiry_time = expiry_time super().__init__(message) class DuplicateResponseError(PermanentError): """ Partner already responded to offer. Raised when duplicate accept/decline response received. Duplicate response should be ignored. """ def __init__(self, message: str, offer_id: str = None, previous_response: str = None): self.offer_id = offer_id self.previous_response = previous_response super().__init__(message)