import logging from django.template.loader import render_to_string from notifier.models import Notifier from notifier.registry import get_notifier_backend logger = logging.getLogger(__name__) def render_notification_content(*, notifier: Notifier, payload: dict) -> str: content = render_to_string(notifier.get_template_name(), payload or {}).strip() if not content: raise ValueError("通知模板渲染结果不能为空") return content def send_notification_with_notifier(*, notifier: Notifier, payload: dict) -> dict: content = render_notification_content(notifier=notifier, payload=payload) backend = get_notifier_backend(notifier.channel) backend_result = backend.notify(notifier=notifier, content=content, context=payload) result = { "notifier_id": notifier.id, "notifier_name": notifier.name, "event_key": notifier.event_key, "channel": notifier.channel, "template_key": notifier.template_key, "status": "sent", **backend_result, } logger.info("[notifier.services] notification sent: %s", result) return result def dispatch_notification_event(*, event_key: str, merchant_id: int, payload: dict | None = None) -> list[dict]: notifiers = list( Notifier.objects.filter( merchant_id=merchant_id, event_key=event_key, is_enabled=True, ).order_by("id") ) if not notifiers: logger.info( "[notifier.services] no enabled notifier matched: event_key=%s merchant_id=%s", event_key, merchant_id, ) return [] results = [] for notifier in notifiers: try: results.append(send_notification_with_notifier(notifier=notifier, payload=payload or {})) except Exception as exc: logger.exception( "[notifier.services] notification failed: notifier_id=%s event_key=%s merchant_id=%s", notifier.id, event_key, merchant_id, ) results.append( { "notifier_id": notifier.id, "notifier_name": notifier.name, "event_key": notifier.event_key, "channel": notifier.channel, "template_key": notifier.template_key, "status": "failed", "error": str(exc), } ) return results def enqueue_notification_event(*, event_key: str, merchant_id: int, payload: dict | None = None) -> str | None: from notifier.tasks import dispatch_notification_event_task try: async_result = dispatch_notification_event_task.delay( event_key=event_key, merchant_id=merchant_id, payload=payload or {}, ) except Exception: logger.exception( "[notifier.services] queue notification task failed: event_key=%s merchant_id=%s", event_key, merchant_id, ) return None logger.info( "[notifier.services] queued notification task: event_key=%s merchant_id=%s task_id=%s", event_key, merchant_id, async_result.id, ) return async_result.id