import functools import logging from dataclasses import dataclass, field from django.db import transaction from django.db.models import Q logger = logging.getLogger(__name__) @dataclass class EventDefinition: name: str description: str = "" example_payload: dict = field(default_factory=dict) schema: dict = field(default_factory=dict) class EventRegistry: _events: dict[str, EventDefinition] = {} @classmethod def register(cls, event_name, *, description="", example_payload=None, schema=None): cls._events[event_name] = EventDefinition( name=event_name, description=description, example_payload=example_payload or {}, schema=schema or {}, ) logger.debug(f"Event registered: {event_name}") @classmethod def emit(cls, event_name, payload: dict): from infrasynth.shared.settings_utils import get_setting from infrasynth.tenancy.context import get_current_tenant from . import dispatch as dispatch_module from .models import OutboundSubscription active_subs = OutboundSubscription.objects.filter( Q(event_name=event_name) | Q(event_name="*"), is_active=True, endpoint__is_active=True, ).select_related("endpoint") tenant = get_current_tenant() tenant_id = str(tenant.pk) if tenant is not None else None backend = get_setting("INFRASYNTH_WEBHOOKS", "DELIVERY_BACKEND", "celery") def _deliver(subscription): if backend == "sync": dispatch_module.deliver_webhook.apply( args=(subscription.id, event_name, payload, subscription.payload_template, tenant_id) ) else: dispatch_module.deliver_webhook.delay( subscription.id, event_name, payload, subscription.payload_template, tenant_id ) with transaction.atomic(): for sub in active_subs: transaction.on_commit(functools.partial(_deliver, sub)) @classmethod def get_registered_events(cls) -> dict[str, EventDefinition]: return dict(cls._events)