v1.1.0: Alembic, pytest, домен и документация
- Миграции PostgreSQL через Alembic; DDL убран из lifespan приложения. - Тесты: health, status, ingress Grafana; моки Vault/Grafana/Forgejo. - Пакет onguard24/domain/ (сущности, шина событий), docs/DOMAIN.md. - Обновлены README, CHANGELOG, ARCHITECTURE. Made-with: Cursor
This commit is contained in:
64
onguard24/domain/events.py
Normal file
64
onguard24/domain/events.py
Normal file
@ -0,0 +1,64 @@
|
||||
"""События домена и подписка модулей (задел; пока in-memory)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from typing import Protocol
|
||||
from uuid import UUID
|
||||
|
||||
from onguard24.domain.entities import Alert
|
||||
|
||||
|
||||
@dataclass
|
||||
class DomainEvent:
|
||||
"""Базовый тип события."""
|
||||
|
||||
name: str = "domain.generic"
|
||||
occurred_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
@dataclass
|
||||
class AlertReceived(DomainEvent):
|
||||
"""Алерт принят в систему (после нормализации)."""
|
||||
|
||||
name: str = "alert.received"
|
||||
alert: Alert | None = None
|
||||
raw_payload_ref: UUID | None = None
|
||||
|
||||
|
||||
Handler = Callable[[DomainEvent], Awaitable[None]]
|
||||
|
||||
|
||||
class Module(Protocol):
|
||||
"""Модуль (schedules, contacts, …) может подписаться на события."""
|
||||
|
||||
@property
|
||||
def name(self) -> str: ...
|
||||
|
||||
async def on_event(self, event: DomainEvent) -> None: ...
|
||||
|
||||
|
||||
class EventBus(Protocol):
|
||||
async def publish(self, event: DomainEvent) -> None: ...
|
||||
|
||||
def subscribe(self, event_name: str, handler: Handler) -> None: ...
|
||||
|
||||
|
||||
class InMemoryEventBus:
|
||||
"""Простая шина для тестов и раннего прототипа."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._subs: dict[str, list[Handler]] = {}
|
||||
|
||||
def subscribe(self, event_name: str, handler: Handler) -> None:
|
||||
self._subs.setdefault(event_name, []).append(handler)
|
||||
|
||||
async def publish(self, event: DomainEvent) -> None:
|
||||
for h in self._subs.get(event.name, []):
|
||||
await h(event)
|
||||
|
||||
async def publish_alert_received(self, alert: Alert, raw_payload_ref: UUID | None = None) -> None:
|
||||
ev = AlertReceived(alert=alert, raw_payload_ref=raw_payload_ref)
|
||||
await self.publish(ev)
|
||||
Reference in New Issue
Block a user