diff --git a/netbox/extras/jobs.py b/netbox/extras/jobs.py index c270833b1e..f64806701b 100644 --- a/netbox/extras/jobs.py +++ b/netbox/extras/jobs.py @@ -2,11 +2,13 @@ import traceback from contextlib import ExitStack -from django.db import transaction +from django.db import router, transaction from django.utils.translation import gettext as _ from core.signals import clear_events +from dcim.models import Device from extras.models import Script as ScriptModel +from netbox.context_managers import event_tracking from netbox.jobs import JobRunner from netbox.registry import registry from utilities.exceptions import AbortScript, AbortTransaction @@ -42,10 +44,18 @@ def run_script(self, script, request, data, commit): # A script can modify multiple models so need to do an atomic lock on # both the default database (for non ChangeLogged models) and potentially # any other database (for ChangeLogged models) - with transaction.atomic(): - script.output = script.run(data, commit) - if not commit: - raise AbortTransaction() + branch_db = router.db_for_write(Device) + with transaction.atomic(using='default'): + # If branch database is different from default, wrap in a second atomic transaction + if branch_db != 'default': + with transaction.atomic(using=branch_db): + script.output = script.run(data, commit) + if not commit: + raise AbortTransaction() + else: + script.output = script.run(data, commit) + if not commit: + raise AbortTransaction() except AbortTransaction: script.log_info(message=_("Database changes have been reverted automatically.")) if script.failed: @@ -108,14 +118,14 @@ def run(self, data, request=None, commit=True, **kwargs): script.request = request self.logger.debug(f"Request ID: {request.id if request else None}") - # Execute the script. If commit is True, wrap it with the event_tracking context manager to ensure we process - # change logging, event rules, etc. if commit: self.logger.info("Executing script (commit enabled)") - with ExitStack() as stack: - for request_processor in registry['request_processors']: - stack.enter_context(request_processor(request)) - self.run_script(script, request, data, commit) else: self.logger.warning("Executing script (commit disabled)") + + with ExitStack() as stack: + for request_processor in registry['request_processors']: + if not commit and request_processor is event_tracking: + continue + stack.enter_context(request_processor(request)) self.run_script(script, request, data, commit)