From 2455660865ba6077c29d0a62b29ed27356b1b9ba Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Tue, 11 Jun 2024 15:37:36 -0400 Subject: [PATCH 01/14] Update scripts.py with rq_queue_name --- netbox/extras/scripts.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/netbox/extras/scripts.py b/netbox/extras/scripts.py index 0e74c3f0de..d0552ec085 100644 --- a/netbox/extras/scripts.py +++ b/netbox/extras/scripts.py @@ -373,6 +373,10 @@ def job_timeout(self): def scheduling_enabled(self): return getattr(self.Meta, 'scheduling_enabled', True) + @classproperty + def rq_queue_name(self): + return getattr(self.Meta, 'rq_queue_name', None) + @property def filename(self): return inspect.getfile(self.__class__) @@ -713,6 +717,7 @@ def _run_script(job): schedule_at=new_scheduled_time, interval=job.interval, job_timeout=script.job_timeout, + rq_queue_name=script.rq_queue_name, data=data, request=request, commit=commit From 259cb5acc03a1085bad7e2b470223db48bb2b188 Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Tue, 11 Jun 2024 15:38:31 -0400 Subject: [PATCH 02/14] Update jobs.py add rq_queue_name --- netbox/core/models/jobs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index b9f0d0b913..2c11f8464f 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -198,7 +198,7 @@ def terminate(self, status=JobStatusChoices.STATUS_COMPLETED, error=None): job_end.send(self) @classmethod - def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None, **kwargs): + def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None,rq_queue_name=None, **kwargs): """ Create a Job instance and enqueue a job using the given callable @@ -211,7 +211,8 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= interval: Recurrence interval (in minutes) """ object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False) - rq_queue_name = get_queue_for_model(object_type.model) + if rq_queue_name == None: + rq_queue_name = get_queue_for_model(object_type.model) queue = django_rq.get_queue(rq_queue_name) status = JobStatusChoices.STATUS_SCHEDULED if schedule_at else JobStatusChoices.STATUS_PENDING job = Job.objects.create( From 99d259341c3296fb47462fc8026af41023aaa439 Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Tue, 11 Jun 2024 15:39:01 -0400 Subject: [PATCH 03/14] Update jobs.py --- netbox/core/models/jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 2c11f8464f..f29ea03f6f 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -198,7 +198,7 @@ def terminate(self, status=JobStatusChoices.STATUS_COMPLETED, error=None): job_end.send(self) @classmethod - def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None,rq_queue_name=None, **kwargs): + def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None, rq_queue_name=None, **kwargs): """ Create a Job instance and enqueue a job using the given callable From 1bc636d91b2b0606c05325d938eb2bc101ce1ce1 Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Tue, 11 Jun 2024 15:50:34 -0400 Subject: [PATCH 04/14] Update jobs.py Lint --- netbox/core/models/jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index f29ea03f6f..68c56dd5a8 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -211,7 +211,7 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= interval: Recurrence interval (in minutes) """ object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False) - if rq_queue_name == None: + if rq_queue_name is None: rq_queue_name = get_queue_for_model(object_type.model) queue = django_rq.get_queue(rq_queue_name) status = JobStatusChoices.STATUS_SCHEDULED if schedule_at else JobStatusChoices.STATUS_PENDING From 3146a4889af224d051cce80e7d2feabc7a6feed7 Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Wed, 12 Jun 2024 23:09:40 -0400 Subject: [PATCH 05/14] Add q_queue_name to docs --- docs/customization/custom-scripts.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 2a8f252aa2..1de97d3318 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -108,6 +108,14 @@ commit_default = False By default, a script can be scheduled for execution at a later time. Setting `scheduling_enabled` to False disables this ability: Only immediate execution will be possible. (This also disables the ability to set a recurring execution interval.) +### `rq_queue_name` + +This will override the standard `QUEUE_MAPPINGS` setting for the be process by the worker. If a worker is not set to monitor any custom mapping the job will never run. + +### `rq_queue_name` + +This will override the standard `QUEUE_MAPPINGS` setting for scripts the be process by the worker. If a worker is not set to monitor any custom mapping the job will never run. + ### `job_timeout` Set the maximum allowed runtime for the script. If not set, `RQ_DEFAULT_TIMEOUT` will be used. From b203c9d916c152fcb2fef7acd9a092d934390348 Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Thu, 13 Jun 2024 14:42:54 -0400 Subject: [PATCH 06/14] Adding rq_queue_name to API and Views --- netbox/core/models/jobs.py | 13 +++++++++---- netbox/extras/api/views.py | 1 + netbox/extras/views.py | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 68c56dd5a8..7960ba5c50 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -1,6 +1,7 @@ import uuid import django_rq +from rq.exceptions import NoSuchJobError from django.conf import settings from django.contrib.contenttypes.fields import GenericForeignKey from django.core.exceptions import ValidationError @@ -152,10 +153,14 @@ def duration(self): def delete(self, *args, **kwargs): super().delete(*args, **kwargs) - - rq_queue_name = get_config().QUEUE_MAPPINGS.get(self.object_type.model, RQ_QUEUE_DEFAULT) - queue = django_rq.get_queue(rq_queue_name) - job = queue.fetch_job(str(self.job_id)) + job = None + for check_queue in get_config().QUEUE_MAPPINGS: + queue = django_rq.get_queue(check_queue) + try: + job = queue.fetch_job(str(self.job_id)) + break + except NoSuchJobError: + pass if job: job.cancel() diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index 05087b2d5e..9927529e09 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -261,6 +261,7 @@ def post(self, request, pk): request=copy_safe_request(request), commit=input_serializer.data['commit'], job_timeout=script.python_class.job_timeout, + rq_queue_name=script.python_class.rq_queue_name, schedule_at=input_serializer.validated_data.get('schedule_at'), interval=input_serializer.validated_data.get('interval') ) diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 82f519c006..b4fda70c24 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -1110,6 +1110,7 @@ def post(self, request, **kwargs): data=form.cleaned_data, request=copy_safe_request(request), job_timeout=script.python_class.job_timeout, + rq_queue_name=script.python_class.rq_queue_name, commit=form.cleaned_data.pop('_commit') ) From 8409c97e1ab07bddf64e5c0d0842b1cbae41eb67 Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Thu, 13 Jun 2024 15:22:30 -0400 Subject: [PATCH 07/14] Default Logic if Queue does not exist --- docs/customization/custom-scripts.md | 6 +----- netbox/core/models/jobs.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 1de97d3318..cf4b3ce660 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -110,11 +110,7 @@ By default, a script can be scheduled for execution at a later time. Setting `sc ### `rq_queue_name` -This will override the standard `QUEUE_MAPPINGS` setting for the be process by the worker. If a worker is not set to monitor any custom mapping the job will never run. - -### `rq_queue_name` - -This will override the standard `QUEUE_MAPPINGS` setting for scripts the be process by the worker. If a worker is not set to monitor any custom mapping the job will never run. +This will override the standard `QUEUE_MAPPINGS` setting for the be process by the worker. If the queue is not found then the default logic found in the settings file will be used. ### `job_timeout` diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 7960ba5c50..ec538edb1d 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -213,12 +213,21 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= name: Name for the job (optional) user: The user responsible for running the job schedule_at: Schedule the job to be executed at the passed date and time + rq_queue_name: Queue name to route the job to for processing interval: Recurrence interval (in minutes) """ object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False) if rq_queue_name is None: rq_queue_name = get_queue_for_model(object_type.model) - queue = django_rq.get_queue(rq_queue_name) + queue = django_rq.get_queue(rq_queue_name) + else: + try: + queue = django_rq.get_queue(rq_queue_name) + except KeyError: + # User defined queue does not exist - return to default logic + rq_queue_name = get_queue_for_model(object_type.model) + queue = django_rq.get_queue(rq_queue_name) + status = JobStatusChoices.STATUS_SCHEDULED if schedule_at else JobStatusChoices.STATUS_PENDING job = Job.objects.create( object_type=object_type, From a28810a98c2d04f08bd3e47403cd39753f88a4a8 Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Fri, 14 Jun 2024 08:24:56 -0400 Subject: [PATCH 08/14] wording --- docs/customization/custom-scripts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index cf4b3ce660..83e9cb7f63 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -110,7 +110,7 @@ By default, a script can be scheduled for execution at a later time. Setting `sc ### `rq_queue_name` -This will override the standard `QUEUE_MAPPINGS` setting for the be process by the worker. If the queue is not found then the default logic found in the settings file will be used. +This will override the standard `QUEUE_MAPPINGS` setting for the script be process by the worker. If the queue is not found then the default logic found in the settings file will be used. ### `job_timeout` From d8868ed15353fab4c818765abbdc7260bb9ec48c Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Fri, 14 Jun 2024 08:26:11 -0400 Subject: [PATCH 09/14] wording --- docs/customization/custom-scripts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 83e9cb7f63..96168ebaae 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -110,7 +110,7 @@ By default, a script can be scheduled for execution at a later time. Setting `sc ### `rq_queue_name` -This will override the standard `QUEUE_MAPPINGS` setting for the script be process by the worker. If the queue is not found then the default logic found in the settings file will be used. +This will override the standard `QUEUE_MAPPINGS` setting for the script to be process by the worker. If the queue is not found then the default logic found in the settings file will be used. ### `job_timeout` From 5676c4abadc928ba00943dcd99329173c67c01ee Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Thu, 20 Jun 2024 18:46:44 -0400 Subject: [PATCH 10/14] Changes requested by arthanson --- netbox/core/models/jobs.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index ec538edb1d..15c0c8471e 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -217,17 +217,16 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= interval: Recurrence interval (in minutes) """ object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False) - if rq_queue_name is None: - rq_queue_name = get_queue_for_model(object_type.model) - queue = django_rq.get_queue(rq_queue_name) - else: + queue = None + if rq_queue_name: try: queue = django_rq.get_queue(rq_queue_name) - except KeyError: - # User defined queue does not exist - return to default logic - rq_queue_name = get_queue_for_model(object_type.model) - queue = django_rq.get_queue(rq_queue_name) - + except: + # User defined queue casued an error - return to default logic + pass + if not queue: + rq_queue_name = get_queue_for_model(object_type.model) + queue = django_rq.get_queue(rq_queue_name) status = JobStatusChoices.STATUS_SCHEDULED if schedule_at else JobStatusChoices.STATUS_PENDING job = Job.objects.create( object_type=object_type, From 421f1aa896d9370156f4c01e4f05eac878ae1870 Mon Sep 17 00:00:00 2001 From: jchambers2012 Date: Thu, 20 Jun 2024 23:44:55 -0400 Subject: [PATCH 11/14] PEP8 Fixes --- netbox/core/models/jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 15c0c8471e..4d1d5c3159 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -221,7 +221,7 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= if rq_queue_name: try: queue = django_rq.get_queue(rq_queue_name) - except: + except Exception: # User defined queue casued an error - return to default logic pass if not queue: From d34a87f5912c2073c5bc41db216f9435ab97b1dd Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Wed, 10 Jul 2024 13:10:29 -0400 Subject: [PATCH 12/14] Add logging for django_rq errors --- netbox/core/models/jobs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 4d1d5c3159..6949ef36ed 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -1,3 +1,4 @@ +import logging import uuid import django_rq @@ -24,6 +25,7 @@ 'Job', ) +logger = logging.getLogger('netbox.core.jobs') class Job(models.Model): """ @@ -222,8 +224,7 @@ def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval= try: queue = django_rq.get_queue(rq_queue_name) except Exception: - # User defined queue casued an error - return to default logic - pass + logger.warning(f"User defined queue '{rq_queue_name}' cased an error or was not found. Falling back to default queue.") if not queue: rq_queue_name = get_queue_for_model(object_type.model) queue = django_rq.get_queue(rq_queue_name) From 9b60d4676ddbdb5e8db57a4a1c16b0910b8181bf Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Wed, 10 Jul 2024 13:13:03 -0400 Subject: [PATCH 13/14] Updated to include RQ reconfigure warning --- docs/customization/custom-scripts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization/custom-scripts.md b/docs/customization/custom-scripts.md index 96168ebaae..aa7b83c86e 100644 --- a/docs/customization/custom-scripts.md +++ b/docs/customization/custom-scripts.md @@ -110,7 +110,7 @@ By default, a script can be scheduled for execution at a later time. Setting `sc ### `rq_queue_name` -This will override the standard `QUEUE_MAPPINGS` setting for the script to be process by the worker. If the queue is not found then the default logic found in the settings file will be used. +This will override the standard `QUEUE_MAPPINGS` setting for the script to be process by the worker. If you use a queue name that is not one of the NetBox provided queues, (IE `high`, `default`, or `low`) then you must reconfigure the RQ working for the new queue. If the queue is not configured then the default logic found in the settings file for [QUEUE_MAPPINGS](../configuration/miscellaneous.md#queue_mappings) will be used. ### `job_timeout` From 470e48e79e42ce8f2e8e0c26654d61da575c1d52 Mon Sep 17 00:00:00 2001 From: "Chambers, Jason" Date: Wed, 10 Jul 2024 13:18:26 -0400 Subject: [PATCH 14/14] PEP8 Fix --- netbox/core/models/jobs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 6949ef36ed..e76bddb0f6 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -27,6 +27,7 @@ logger = logging.getLogger('netbox.core.jobs') + class Job(models.Model): """ Tracks the lifecycle of a job which represents a background task (e.g. the execution of a custom script).