Преглед изворни кода

Closes #4173: Return graceful error message when webhook queuing fails

Jeremy Stretch пре 6 година
родитељ
комит
9128dc961c

+ 4 - 0
docs/release-notes/version-2.7.md

@@ -1,5 +1,9 @@
 # v2.7.8 (FUTURE)
 
+## Enhancements
+
+* [#4173](https://github.com/netbox-community/netbox/issues/4173) - Return graceful error message when webhook queuing fails
+
 ## Bug Fixes
 
 * [#4224](https://github.com/netbox-community/netbox/issues/4224) - Fix display of rear device image if front image is not defined 

+ 14 - 1
netbox/extras/middleware.py

@@ -5,11 +5,14 @@ from copy import deepcopy
 from datetime import timedelta
 
 from django.conf import settings
+from django.contrib import messages
 from django.db.models.signals import pre_delete, post_save
 from django.utils import timezone
 from django_prometheus.models import model_deletes, model_inserts, model_updates
+from redis.exceptions import RedisError
 
 from extras.utils import is_taggable
+from utilities.api import is_api_request
 from utilities.querysets import DummyQuerySet
 from .choices import ObjectChangeActionChoices
 from .models import ObjectChange
@@ -99,6 +102,7 @@ class ObjectChangeMiddleware(object):
             return response
 
         # Create records for any cached objects that were changed.
+        redis_failed = False
         for instance, action in _thread_locals.changed_objects:
 
             # Refresh cached custom field values
@@ -114,7 +118,16 @@ class ObjectChangeMiddleware(object):
                 objectchange.save()
 
             # Enqueue webhooks
-            enqueue_webhooks(instance, request.user, request.id, action)
+            try:
+                enqueue_webhooks(instance, request.user, request.id, action)
+            except RedisError as e:
+                if not redis_failed and not is_api_request(request):
+                    messages.error(
+                        request,
+                        "There was an error processing webhooks for this request. Check that the Redis service is "
+                        "running and reachable. The full error details were: {}".format(e)
+                    )
+                    redis_failed = True
 
             # Increment metric counters
             if action == ObjectChangeActionChoices.ACTION_CREATE:

+ 9 - 0
netbox/utilities/api.py

@@ -6,6 +6,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDoesNotExist
 from django.db.models import ManyToManyField, ProtectedError
 from django.http import Http404
+from django.urls import reverse
 from rest_framework.exceptions import APIException
 from rest_framework.permissions import BasePermission
 from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
@@ -41,6 +42,14 @@ def get_serializer_for_model(model, prefix=''):
         )
 
 
+def is_api_request(request):
+    """
+    Return True of the request is being made via the REST API.
+    """
+    api_path = reverse('api-root')
+    return request.path_info.startswith(api_path)
+
+
 #
 # Authentication
 #

+ 2 - 2
netbox/utilities/middleware.py

@@ -5,6 +5,7 @@ from django.db import ProgrammingError
 from django.http import Http404, HttpResponseRedirect
 from django.urls import reverse
 
+from .api import is_api_request
 from .views import server_error
 
 
@@ -38,9 +39,8 @@ class APIVersionMiddleware(object):
         self.get_response = get_response
 
     def __call__(self, request):
-        api_path = reverse('api-root')
         response = self.get_response(request)
-        if request.path_info.startswith(api_path):
+        if is_api_request(request):
             response['API-Version'] = settings.REST_FRAMEWORK_VERSION
         return response