From 011b68758adaa674d53eceb260ea2a5325380058 Mon Sep 17 00:00:00 2001 From: Jonas Linter Date: Thu, 27 Nov 2025 14:47:05 +0100 Subject: [PATCH] Catch integrity errors gracefully instead of dumping a giant stacktrace --- src/alpine_bits_python/webhook_processor.py | 25 +++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/alpine_bits_python/webhook_processor.py b/src/alpine_bits_python/webhook_processor.py index 3215b6c..6eb0d68 100644 --- a/src/alpine_bits_python/webhook_processor.py +++ b/src/alpine_bits_python/webhook_processor.py @@ -1,21 +1,19 @@ """Webhook processor interface and implementations.""" -from abc import ABC, abstractmethod import asyncio from datetime import date, datetime from typing import Any, Protocol from fastapi import HTTPException, Request +from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession -from alpine_bits_python.config_loader import get_advertising_account_ids from alpine_bits_python.auth import generate_unique_id +from alpine_bits_python.config_loader import get_advertising_account_ids from alpine_bits_python.customer_service import CustomerService from alpine_bits_python.reservation_service import ReservationService from alpine_bits_python.schemas import ReservationData - - from .db import Hotel, WebhookRequest from .logging_config import get_logger @@ -52,6 +50,7 @@ class WebhookProcessorProtocol(Protocol): Raises: HTTPException on processing errors + """ ... @@ -68,6 +67,7 @@ class WebhookProcessorRegistry: Args: processor: Processor instance to register + """ self._processors[processor.webhook_type] = processor _LOGGER.info("Registered webhook processor: %s", processor.webhook_type) @@ -80,6 +80,7 @@ class WebhookProcessorRegistry: Returns: Processor instance or None if not found + """ return self._processors.get(webhook_type) @@ -252,9 +253,15 @@ async def process_wix_form_submission(request: Request, data: dict[str, Any], db # Use ReservationService to create reservation reservation_service = ReservationService(db) - db_reservation = await reservation_service.create_reservation( - reservation, db_customer.id - ) + try: + db_reservation = await reservation_service.create_reservation( + reservation, db_customer.id + ) + except IntegrityError as e: + _LOGGER.exception("Database integrity error creating reservation: %s", e) + raise HTTPException( + status_code=500, detail="Database error creating reservation" + ) from e async def push_event(): # Fire event for listeners (push, etc.) - hotel-specific dispatch @@ -314,6 +321,7 @@ class WixFormProcessor: Returns: Response dict with status and details + """ # Import here to avoid circular dependency @@ -613,9 +621,8 @@ class GenericWebhookProcessor: Returns: Response dict with status and details + """ - - # Call existing processing function result = await process_generic_webhook_submission(request, payload, db_session)