diff --git a/CHANGES/+deferred_task_args.feature b/CHANGES/+deferred_task_args.feature new file mode 100644 index 0000000000..5e8125ff44 --- /dev/null +++ b/CHANGES/+deferred_task_args.feature @@ -0,0 +1,2 @@ +Improved performance when handling tasks by deferred loading of encrypted args. +This also allows seeing and purging tasks in case the symmetric db key was lost. diff --git a/pulpcore/app/models/task.py b/pulpcore/app/models/task.py index dac5af1041..c33db280da 100644 --- a/pulpcore/app/models/task.py +++ b/pulpcore/app/models/task.py @@ -63,6 +63,14 @@ class Meta: unique_together = ("task", "name") +class TaskManager(models.Manager): + def get_queryset(self): + # Always make encrypted args deferred. + # This will prevent a lot of issues when the fernet key is lost. + # Only task workers need to be able to read these args anyway. + return super().get_queryset().defer("enc_args", "enc_kwargs") + + class Task(BaseModel, AutoAddObjPermsMixin): """ Represents a task @@ -88,6 +96,8 @@ class Task(BaseModel, AutoAddObjPermsMixin): pulp_domain (models.ForeignKey): The domain the Task is a part of """ + objects = TaskManager() + state = models.TextField(choices=TASK_CHOICES) name = models.TextField() logging_cid = models.TextField(db_index=True) @@ -285,8 +295,10 @@ def refresh_from_db(self, using=None, fields=None, **kwargs): # loaded. if fields is not None: fields = set(fields) - deferred_fields = self.get_deferred_fields() - # If any deferred field is going to be loaded + deferred_fields = { + field for field in self.get_deferred_fields() if not field.startswith("enc_") + } + # If any state related deferred field is going to be loaded if fields.intersection(deferred_fields): # then load all of them fields = fields.union(deferred_fields) diff --git a/pulpcore/tasking/_util.py b/pulpcore/tasking/_util.py index 8aa6e56081..6d352a3d4a 100644 --- a/pulpcore/tasking/_util.py +++ b/pulpcore/tasking/_util.py @@ -95,7 +95,8 @@ def perform_task(task_pk, task_working_dir_rel_path): signal.signal(signal.SIGUSR1, child_signal_handler) # All processes need to create their own postgres connection connection.connection = None - task = Task.objects.select_related("pulp_domain").get(pk=task_pk) + # enc_args and enc_kwargs are deferred by default but we actually want them + task = Task.objects.defer(None).select_related("pulp_domain").get(pk=task_pk) user = get_users_with_perms(task, with_group_users=False).first() # Isolate from the parent asyncio. asyncio.set_event_loop(asyncio.new_event_loop())