Relax requirement for Jobs to reference a specific object

This commit is contained in:
Jeremy Stretch 2024-07-24 15:58:32 -04:00
parent 62380fb605
commit d6432fbcb8
3 changed files with 37 additions and 26 deletions

View File

@ -0,0 +1,24 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('core', '0011_move_objectchange'),
]
operations = [
migrations.AlterField(
model_name='job',
name='object_type',
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='jobs',
to='contenttypes.contenttype'
),
),
]

View File

@ -31,6 +31,8 @@ class Job(models.Model):
to='contenttypes.ContentType',
related_name='jobs',
on_delete=models.CASCADE,
blank=True,
null=True
)
object_id = models.PositiveBigIntegerField(
blank=True,
@ -197,13 +199,13 @@ class Job(models.Model):
job_end.send(self)
@classmethod
def enqueue(cls, func, instance, name='', user=None, schedule_at=None, interval=None, run_now=False, **kwargs):
def enqueue(cls, func, instance=None, name='', user=None, schedule_at=None, interval=None, run_now=False, **kwargs):
"""
Create a Job instance and enqueue a job using the given callable
Args:
func: The callable object to be enqueued for execution
instance: The NetBox object to which this job pertains
instance: The NetBox object to which this job pertains (optional)
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
@ -211,13 +213,17 @@ class Job(models.Model):
run_now: Run the job immediately without scheduling it in the background. Should be used for interactive
management commands only.
"""
object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False)
if instance:
object_type = ObjectType.objects.get_for_model(instance, for_concrete_model=False)
object_id = instance.pk
else:
object_type = object_id = 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(
object_type=object_type,
object_id=instance.pk,
object_id=object_id,
name=name,
status=status,
scheduled=schedule_at,

View File

@ -161,30 +161,11 @@ class SystemJob(ScheduledJob):
for system background tasks.
The main use case for this method is to schedule jobs programmatically instead of using user events, e.g. to start
jobs when the plugin is loaded in NetBox. For this purpose, the `setup()` method can be used to setup a new schedule
outside of the request-response cycle. It will register the new schedule right after all plugins are loaded and the
database is connected. Then `schedule()` will take care of scheduling a single job at a time.
jobs when the plugin is loaded in NetBox. For this purpose, the `setup()` method can be used to set up a new
schedule outside the request-response cycle. It will register the new schedule right after all plugins are loaded
and the database is connected. Then `schedule()` will take care of scheduling a single job at a time.
"""
@classmethod
def enqueue(cls, *args, **kwargs):
kwargs.pop('instance', None)
return super().enqueue(instance=Job(), *args, **kwargs)
@classmethod
def schedule(cls, *args, **kwargs):
kwargs.pop('instance', None)
return super().schedule(instance=Job(), *args, **kwargs)
@classmethod
def handle(cls, job, *args, **kwargs):
# A job requires a related object to be handled, or internal methods will fail. To avoid adding an extra model
# for this, the existing job object is used as a reference. This is not ideal, but it works for this purpose.
job.object = job
job.object_id = None # Hide changes from UI
super().handle(job, *args, **kwargs)
@classmethod
def setup(cls, *args, **kwargs):
"""