Files
asf/packages/asf-events/asf_events/base.py
T
2026-09-08 07:21:34 -04:00

66 lines
2.0 KiB
Python

"""Base event envelope + job request envelope.
Every RabbitMQ message is either:
1. An ``ASFEvent`` subclass → a fact that happened (domain event).
2. A ``JobRequestEnvelope`` → a unit of work to be executed (job).
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import Any, Optional, Dict
from uuid import uuid4, UUID
from pydantic import Field
from asf_domain.base import ASFBaseModel, UTCDatetime, JobType, JobPriority
class ASFEvent(ASFBaseModel):
"""Abstract base for every domain event published on RabbitMQ.
Semantics: facts that happened, never commands.
Naming pattern: <Noun>.<Ved> (artifact.created, deployment.completed).
"""
event_id: UUID = Field(default_factory=uuid4)
event_type: str = Field(
...,
max_length=128,
description="Dot-delimited routing key e.g. 'artifact.created'.",
)
timestamp: UTCDatetime = Field(
default_factory=lambda: datetime.now(tz=timezone.utc)
)
tenant_id: UUID = Field(..., description="Owning tenant.")
project_id: Optional[UUID] = None
correlation_id: Optional[str] = Field(None, max_length=128)
causation_id: Optional[str] = Field(
None,
max_length=128,
description="Id of the previous event / request that caused this one.",
)
payload: Dict[str, Any] = Field(default_factory=dict)
class JobRequestEnvelope(ASFBaseModel):
"""Envelope delivered to a RabbitMQ worker queue.
The worker performs the work, then updates the corresponding Mongo
``Job`` record (its id is in this envelope). RabbitMQ is NOT the
permanent job state store — MongoDB is.
"""
job_id: UUID
tenant_id: UUID
project_id: Optional[UUID] = None
type: JobType
priority: JobPriority = JobPriority.NORMAL
correlation_id: Optional[str] = None
payload: Dict[str, Any] = Field(default_factory=dict)
reply_to: Optional[str] = Field(
None,
max_length=255,
description="Optional queue/routing-key for completion events.",
)