mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-05 01:14:58 +03:00
54 lines
1.7 KiB
Python
54 lines
1.7 KiB
Python
from dataclasses import dataclass
|
|
from datetime import timedelta
|
|
from typing import Any
|
|
|
|
from django.db import transaction
|
|
from django.utils import timezone
|
|
|
|
from hub_platform.events.context import get_correlation_id
|
|
from hub_platform.events.models import OutboxEvent, OutboxStatus
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DomainEvent:
|
|
aggregate_type: str
|
|
aggregate_id: str
|
|
event_type: str
|
|
payload: dict[str, Any]
|
|
|
|
|
|
def enqueue_event(event: DomainEvent) -> OutboxEvent:
|
|
return OutboxEvent.objects.create(
|
|
aggregate_type=event.aggregate_type,
|
|
aggregate_id=event.aggregate_id,
|
|
event_type=event.event_type,
|
|
payload=event.payload,
|
|
correlation_id=get_correlation_id(),
|
|
)
|
|
|
|
|
|
def mark_retry(event: OutboxEvent, error: str, max_attempts: int = 5) -> None:
|
|
event.attempts += 1
|
|
event.last_error = error
|
|
event.status = OutboxStatus.DEAD_LETTER if event.attempts >= max_attempts else OutboxStatus.FAILED
|
|
event.next_attempt_at = timezone.now() + timedelta(seconds=min(300, 2**event.attempts))
|
|
event.save(update_fields=["attempts", "last_error", "status", "next_attempt_at"])
|
|
|
|
|
|
def claim_next_outbox_event() -> OutboxEvent | None:
|
|
with transaction.atomic():
|
|
event = (
|
|
OutboxEvent.objects.select_for_update(skip_locked=True)
|
|
.filter(
|
|
status__in=[OutboxStatus.PENDING, OutboxStatus.FAILED],
|
|
next_attempt_at__lte=timezone.now(),
|
|
)
|
|
.order_by("next_attempt_at", "created_at")
|
|
.first()
|
|
)
|
|
if event is None:
|
|
return None
|
|
event.status = OutboxStatus.PROCESSING
|
|
event.save(update_fields=["status"])
|
|
return event
|