diff --git a/app/services/handlers/abstract_handler.py b/app/services/handlers/abstract_handler.py index 8c607f7..96b74fb 100644 --- a/app/services/handlers/abstract_handler.py +++ b/app/services/handlers/abstract_handler.py @@ -4,7 +4,10 @@ from app.commons.logging.types import AsyncLoggerContextCreator, LogRecord from app.constants import HTTPStatusCodes -from app.services.handlers.gateway_priority import PriorityGatewaySelection +from app.services.handlers.gateway_priority import ( + NoGatewayPriorityConfigured, + PriorityGatewaySelection, +) from app.services.handlers.notifier import Notifier logger = logging.getLogger() @@ -81,10 +84,22 @@ async def notify(cls, to, message, **kwargs): # If log_info is not present use log_id as `-1`` log_info = kwargs.pop("log_info", LogRecord(log_id="-1")) provider, response = None, None - for n_attempts in range(cls.ENABLED_GATEWAYS_COUNT): - gateway = cls.select_gateway( - n_attempts, cls._get_priority_logic_data(to, **kwargs) + if not cls.ENABLED_GATEWAYS_COUNT: + logger.error( + "No gateways enabled for channel %s; cannot send notification.", + cls.CHANNEL, ) + return provider, response + for n_attempts in range(cls.ENABLED_GATEWAYS_COUNT): + try: + gateway = cls.select_gateway( + n_attempts, cls._get_priority_logic_data(to, **kwargs) + ) + except NoGatewayPriorityConfigured as exc: + logger.error( + "Skipping send for channel %s: %s", cls.CHANNEL, exc, + ) + return provider, response provider = cls.PROVIDERS[gateway] response = await provider.send_notification(to, message, **kwargs) async with cls.logger as log: diff --git a/app/services/handlers/gateway_priority.py b/app/services/handlers/gateway_priority.py index f69f67b..b6308cd 100644 --- a/app/services/handlers/gateway_priority.py +++ b/app/services/handlers/gateway_priority.py @@ -1,5 +1,12 @@ +import logging from abc import ABC, abstractmethod +logger = logging.getLogger(__name__) + + +class NoGatewayPriorityConfigured(Exception): + """Raised when a channel has no gateway priority configured.""" + class PriorityGatewaySelection(ABC): """ @@ -39,15 +46,30 @@ def select_gateway(cls, n_attempts: int, request_data: dict) -> str: """ priority_logic_expression = cls.get_priority_logic() - current_priority = cls.get_default_priority() + default_priority = cls.get_default_priority() or [] + current_priority = list(default_priority) if priority_logic_expression: # execute the priority logic to get the priority order of gateways try: # Never delete the 'data' declaration below. It is used in the eval statement. data = request_data current_priority = eval(priority_logic_expression) - except Exception: - # Log the exception and fallback to default priority order - pass - total_gateways = min(len(cls.get_default_priority()), len(current_priority)) + except Exception as exc: + logger.warning( + "Priority logic evaluation failed for channel %s; falling back to default priority. Error: %s", + cls.__name__, + exc, + ) + current_priority = list(default_priority) + + if not current_priority or not default_priority: + logger.error( + "No gateway priority configured for channel %s; cannot select a gateway.", + cls.__name__, + ) + raise NoGatewayPriorityConfigured( + f"No gateway priority configured for channel {cls.__name__}" + ) + + total_gateways = min(len(default_priority), len(current_priority)) return current_priority[n_attempts % total_gateways]