Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions app/services/handlers/abstract_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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:
Expand Down
32 changes: 27 additions & 5 deletions app/services/handlers/gateway_priority.py
Original file line number Diff line number Diff line change
@@ -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):
"""
Expand Down Expand Up @@ -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]