diff --git a/docs/development/application-registry.md b/docs/development/application-registry.md index 570563431..fc96bfd76 100644 --- a/docs/development/application-registry.md +++ b/docs/development/application-registry.md @@ -49,6 +49,10 @@ This key lists all models which have been registered in NetBox which are not des This store maintains all registered items for plugins, such as navigation menus, template extensions, etc. +### `request_processors` + +A list of context managers to invoke when processing a request e.g. in middleware or when executing a background job. Request processors can be registered with the `@register_request_processor` decorator. + ### `search` A dictionary mapping each model (identified by its app and label) to its search index class, if one has been registered for it. diff --git a/netbox/netbox/context_managers.py b/netbox/netbox/context_managers.py index ca434df82..7b01cce94 100644 --- a/netbox/netbox/context_managers.py +++ b/netbox/netbox/context_managers.py @@ -1,9 +1,11 @@ from contextlib import contextmanager from netbox.context import current_request, events_queue +from netbox.utils import register_request_processor from extras.events import flush_events +@register_request_processor @contextmanager def event_tracking(request): """ diff --git a/netbox/netbox/middleware.py b/netbox/netbox/middleware.py index 8012965a4..b9424bd7c 100644 --- a/netbox/netbox/middleware.py +++ b/netbox/netbox/middleware.py @@ -1,3 +1,5 @@ +from contextlib import ExitStack + import logging import uuid @@ -10,7 +12,7 @@ from django.db.utils import InternalError from django.http import Http404, HttpResponseRedirect from netbox.config import clear_config, get_config -from netbox.context_managers import event_tracking +from netbox.registry import registry from netbox.views import handler_500 from utilities.api import is_api_request from utilities.error_handlers import handle_rest_api_exception @@ -32,8 +34,10 @@ class CoreMiddleware: # Assign a random unique ID to the request. This will be used for change logging. request.id = uuid.uuid4() - # Enable the event_tracking context manager and process the request. - with event_tracking(request): + # Apply all registered request processors + with ExitStack() as stack: + for request_processor in registry['request_processors']: + stack.enter_context(request_processor(request)) response = self.get_response(request) # Check if language cookie should be renewed diff --git a/netbox/netbox/registry.py b/netbox/netbox/registry.py index 0920cbccf..5dc5efb77 100644 --- a/netbox/netbox/registry.py +++ b/netbox/netbox/registry.py @@ -29,6 +29,7 @@ registry = Registry({ 'model_features': dict(), 'models': collections.defaultdict(set), 'plugins': dict(), + 'request_processors': list(), 'search': dict(), 'tables': collections.defaultdict(dict), 'views': collections.defaultdict(dict), diff --git a/netbox/netbox/utils.py b/netbox/netbox/utils.py index f27d1b5f7..f2c34722c 100644 --- a/netbox/netbox/utils.py +++ b/netbox/netbox/utils.py @@ -3,6 +3,7 @@ from netbox.registry import registry __all__ = ( 'get_data_backend_choices', 'register_data_backend', + 'register_request_processor', ) @@ -24,3 +25,12 @@ def register_data_backend(): return cls return _wrapper + + +def register_request_processor(func): + """ + Decorator for registering a request processor. + """ + registry['request_processors'].append(func) + + return func