From a3ad12990707b6f8d988310e168039747cf351d5 Mon Sep 17 00:00:00 2001 From: AlanJaeger Date: Tue, 22 Oct 2024 16:45:51 -0300 Subject: [PATCH] feature: moving retry logic to request callback --- chats/apps/api/v1/rooms/viewsets.py | 48 ++++++-------------------- chats/apps/rooms/models.py | 52 +++++++++++++++++++---------- 2 files changed, 46 insertions(+), 54 deletions(-) diff --git a/chats/apps/api/v1/rooms/viewsets.py b/chats/apps/api/v1/rooms/viewsets.py index 9defe6b0..8ff4ed6e 100644 --- a/chats/apps/api/v1/rooms/viewsets.py +++ b/chats/apps/api/v1/rooms/viewsets.py @@ -153,43 +153,17 @@ def close( # Add send room notification to the channels group instance = self.get_object() - for attempt in range(settings.MAX_RETRIES): - try: - with transaction.atomic(): - tags = request.data.get("tags", None) - instance.close(tags, "agent") - serialized_data = RoomSerializer(instance=instance) - - try: - instance.notify_queue("close", callback=True) - except HTTPError as http_error: - if http_error.response.status_code == 404: - sentry_sdk.capture_message( - f"Callback return 404 ERROR CODE to: {instance}" - ) - else: - raise - except RequestException as error: - sentry_sdk.capture_exception(error) - raise - instance.notify_user("close") - - if not settings.ACTIVATE_CALC_METRICS: - return Response(serialized_data.data, status=status.HTTP_200_OK) - - close_room(str(instance.pk)) - return Response(serialized_data.data, status=status.HTTP_200_OK) - - except DatabaseError as db_error: - if attempt < settings.MAX_RETRIES - 1: - delay = settings.RETRY_DELAY_SECONDS * (2**attempt) - time.sleep(delay) - continue - else: - return Response( - {"error": f"Transaction failed after retries: {str(db_error)}"}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR, - ) + tags = request.data.get("tags", None) + instance.close(tags, "agent") + serialized_data = RoomSerializer(instance=instance) + instance.notify_queue("close", callback=True) + instance.notify_user("close") + + if not settings.ACTIVATE_CALC_METRICS: + return Response(serialized_data.data, status=status.HTTP_200_OK) + + close_room(str(instance.pk)) + return Response(serialized_data.data, status=status.HTTP_200_OK) def perform_create(self, serializer): serializer.save() diff --git a/chats/apps/rooms/models.py b/chats/apps/rooms/models.py index 63b87e7f..3a22c67f 100644 --- a/chats/apps/rooms/models.py +++ b/chats/apps/rooms/models.py @@ -1,5 +1,6 @@ import json from datetime import timedelta +import time import requests from django.core.exceptions import ObjectDoesNotExist @@ -9,9 +10,12 @@ from django.utils.translation import gettext_lazy as _ from requests.exceptions import RequestException from rest_framework.exceptions import ValidationError +import sentry_sdk from chats.core.models import BaseModel from chats.utils.websockets import send_channels_group +from django.db import DatabaseError, transaction +from django.conf import settings class Room(BaseModel): @@ -180,23 +184,37 @@ def request_callback(self, room_data: dict): if self.callback_url is None: return None - try: - response = requests.post( - self.callback_url, - data=json.dumps( - {"type": "room.update", "content": room_data}, - sort_keys=True, - indent=1, - cls=DjangoJSONEncoder, - ), - headers={"content-type": "application/json"}, - ) - response.raise_for_status() - - except RequestException as error: - raise RuntimeError( - f"Failed to send callback to {self.callback_url}: {str(error)}" - ) + for attempt in range(settings.MAX_RETRIES): + try: + response = requests.post( + self.callback_url, + data=json.dumps( + {"type": "room.update", "content": room_data}, + sort_keys=True, + indent=1, + cls=DjangoJSONEncoder, + ), + headers={"content-type": "application/json"}, + ) + + if response.status_code == 404: + sentry_sdk.capture_message( + f"Callback returned 404 ERROR for URL: {self.callback_url} with data: {room_data}" + ) + return None + else: + response.raise_for_status() + + return response + + except RequestException as error: + if attempt < settings.MAX_RETRIES - 1: + delay = settings.RETRY_DELAY_SECONDS * (2**attempt) + time.sleep(delay) + else: + raise RuntimeError( + f"Failed to send callback to {self.callback_url} after {attempt + 1} attempts: {str(error)}" + ) def base_notification(self, content, action): if self.user: