""" Event Bus for async communication between services """ from typing import Dict, List, Callable, Any from dataclasses import dataclass from datetime import datetime from enum import Enum import asyncio import json class EventType(str, Enum): """Event types""" OBSERVATION_CREATED = "observation.created" OBSERVATION_UPDATED = "observation.updated" SIGNAL_GENERATED = "signal.generated" DECISION_MADE = "decision.made" OUTCOME_RECORDED = "outcome.recorded" INTERVENTION_STARTED = "intervention.started" INTERVENTION_COMPLETED = "intervention.completed" MODEL_UPDATED = "model.updated" PLATFORM_CHANGE = "platform.change" SYNC_COMPLETED = "sync.completed" ALERT_TRIGGERED = "alert.triggered" @dataclass class Event: """Platform event""" event_id: str event_type: EventType payload: Dict[str, Any] timestamp: str source: str correlation_id: Optional[str] = None def to_dict(self) -> Dict: return { "event_id": self.event_id, "event_type": self.event_type.value, "payload": self.payload, "timestamp": self.timestamp, "source": self.source, "correlation_id": self.correlation_id } class EventBus: """Event bus for async communication""" def __init__(self): self.subscribers: Dict[EventType, List[Callable]] = {} self.event_history: List[Event] = [] self.max_history = 10000 def subscribe(self, event_type: EventType, handler: Callable): """Subscribe to an event type""" if event_type not in self.subscribers: self.subscribers[event_type] = [] self.subscribers[event_type].append(handler) def unsubscribe(self, event_type: EventType, handler: Callable): """Unsubscribe from an event type""" if event_type in self.subscribers: if handler in self.subscribers[event_type]: self.subscribers[event_type].remove(handler) async def publish(self, event: Event): """Publish an event""" # Store in history self.event_history.append(event) if len(self.event_history) > self.max_history: self.event_history = self.event_history[-self.max_history:] # Notify subscribers handlers = self.subscribers.get(event.event_type, []) # Run handlers concurrently if handlers: await asyncio.gather( *[self._run_handler(handler, event) for handler in handlers], return_exceptions=True ) async def _run_handler(self, handler: Callable, event: Event): """Run a handler with error handling""" try: if asyncio.iscoroutinefunction(handler): await handler(event) else: handler(event) except Exception as e: print(f"Event handler error: {e}") def get_events(self, event_type: Optional[EventType] = None, limit: int = 100) -> List[Dict]: """Get recent events""" events = self.event_history if event_type: events = [e for e in events if e.event_type == event_type] return [e.to_dict() for e in events[-limit:]] def get_stats(self) -> Dict: """Get event bus statistics""" return { "total_events": len(self.event_history), "subscribers": { event_type.value: len(handlers) for event_type, handlers in self.subscribers.items() }, "event_types": list(set(e.event_type.value for e in self.event_history)) } # Global event bus event_bus = EventBus() # Example event handlers async def on_observation_created(event: Event): """Handle observation created event""" print(f"New observation: {event.payload.get('observation_id')}") # Trigger signal generation # Trigger sync to targets # Update global model async def on_decision_made(event: Event): """Handle decision made event""" print(f"New decision: {event.payload.get('decision_type')}") # Notify stakeholders # Update decision knowledge # Trigger autonomous actions if enabled async def on_outcome_recorded(event: Event): """Handle outcome recorded event""" print(f"New outcome: {event.payload.get('intervention_id')}") # Update evidence engine # Update global model # Generate insights # Broadcast to connected clients # Register handlers event_bus.subscribe(EventType.OBSERVATION_CREATED, on_observation_created) event_bus.subscribe(EventType.DECISION_MADE, on_decision_made) event_bus.subscribe(EventType.OUTCOME_RECORDED, on_outcome_recorded)