feat: add outbound webhook event framework
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Index, Integer, String, Text
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
|
||||
class WebhookEndpoint(Base):
|
||||
"""Outbound webhook endpoint configured by an operator."""
|
||||
|
||||
__tablename__ = "webhook_endpoints"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
name = Column(String(120), nullable=False)
|
||||
url = Column(Text, nullable=False)
|
||||
secret = Column(Text, nullable=False)
|
||||
event_types = Column(Text, nullable=False, default="*")
|
||||
enabled = Column(Boolean, default=True, nullable=False, index=True)
|
||||
max_attempts = Column(Integer, default=5, nullable=False)
|
||||
timeout_seconds = Column(Integer, default=10, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
last_success_at = Column(DateTime, nullable=True, index=True)
|
||||
last_failure_at = Column(DateTime, nullable=True, index=True)
|
||||
failure_count = Column(Integer, default=0, nullable=False)
|
||||
|
||||
__table_args__ = (Index("ix_webhook_endpoints_enabled_events", "enabled", "event_types"),)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<WebhookEndpoint {self.name} enabled={self.enabled}>"
|
||||
|
||||
|
||||
class WebhookDelivery(Base):
|
||||
"""Single outbound webhook delivery attempt state."""
|
||||
|
||||
__tablename__ = "webhook_deliveries"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
endpoint_id = Column(Integer, ForeignKey("webhook_endpoints.id"), nullable=False, index=True)
|
||||
event_type = Column(String(80), nullable=False, index=True)
|
||||
payload = Column(Text, nullable=False)
|
||||
idempotency_key = Column(String(160), nullable=False, index=True)
|
||||
status = Column(String(24), nullable=False, default="pending", index=True)
|
||||
attempt_count = Column(Integer, default=0, nullable=False)
|
||||
max_attempts = Column(Integer, default=5, nullable=False)
|
||||
next_attempt_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
last_attempt_at = Column(DateTime, nullable=True, index=True)
|
||||
delivered_at = Column(DateTime, nullable=True, index=True)
|
||||
last_status_code = Column(Integer, nullable=True)
|
||||
last_error = Column(Text, nullable=True)
|
||||
response_excerpt = Column(Text, nullable=True)
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False, index=True)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
__table_args__ = (
|
||||
Index(
|
||||
"ix_webhook_delivery_endpoint_idempotency",
|
||||
"endpoint_id",
|
||||
"idempotency_key",
|
||||
unique=True,
|
||||
),
|
||||
Index("ix_webhook_delivery_due", "status", "next_attempt_at"),
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<WebhookDelivery endpoint={self.endpoint_id} event={self.event_type} status={self.status}>"
|
||||
Reference in New Issue
Block a user