From abff0a4fe83a89897204726bef31790031720247 Mon Sep 17 00:00:00 2001 From: David Davis Date: Sat, 18 Apr 2026 11:55:04 +0000 Subject: [PATCH] Expose TaskSchedule in plugin API and add ags/kwargs The [plugin writer docs say that plugin writers can schedule tasks](https://pulpproject.org/pulpcore/docs/dev/learn/other/task-scheduling) but the TaskSchedule model doesn't appear to be exposed in the plugin API. Also, add encrypted JSONFields for args and kwargs to TaskSchedule so that plugins can store keyword arguments to pass to tasks when they are dispatched on schedule. The dispatch logic now forwards these to dispatch(). closes #7608 Generated by: GitHub Copilot (Claude) --- CHANGES/plugin_api/7608.feature | 4 ++++ docs/dev/learn/other/task-scheduling.md | 23 ++++++++++++++++++ .../0150_taskschedule_task_kwargs.py | 24 +++++++++++++++++++ pulpcore/app/models/task.py | 2 ++ pulpcore/plugin/models/__init__.py | 2 ++ pulpcore/plugin/serializers/__init__.py | 2 ++ pulpcore/tasking/_util.py | 2 ++ 7 files changed, 59 insertions(+) create mode 100644 CHANGES/plugin_api/7608.feature create mode 100644 pulpcore/app/migrations/0150_taskschedule_task_kwargs.py diff --git a/CHANGES/plugin_api/7608.feature b/CHANGES/plugin_api/7608.feature new file mode 100644 index 00000000000..6aaa7706b96 --- /dev/null +++ b/CHANGES/plugin_api/7608.feature @@ -0,0 +1,4 @@ +Added `task_args` and `task_kwargs` fields to `TaskSchedule`, allowing plugins to store positional +and keyword arguments that are forwarded to tasks when they are dispatched on schedule. Both fields +are encrypted at rest. `TaskSchedule` and `TaskScheduleSerializer` are now exposed via the plugin +API. diff --git a/docs/dev/learn/other/task-scheduling.md b/docs/dev/learn/other/task-scheduling.md index 92ebecce1de..d8662f90b60 100644 --- a/docs/dev/learn/other/task-scheduling.md +++ b/docs/dev/learn/other/task-scheduling.md @@ -14,3 +14,26 @@ therefore scheduled task dispatching will be missed if all workers are offline. window, overdue schedules will dispatch at most one task, but down to timing, they may be rescheduled shortly thereafter. The task schedule API at `/pulp/api/v3/task-schedules/` is provided to read the tasks schedules. + +## Passing Arguments to Scheduled Tasks + +The `task_args` and `task_kwargs` fields on `TaskSchedule` allow plugin writers to store positional +and keyword arguments that will be forwarded to the task function each time it is dispatched. This +is useful when a scheduled task needs to operate on a specific resource or with specific options. + +```python +from datetime import timedelta +from pulpcore.plugin.models import TaskSchedule + +TaskSchedule( + name="my-plugin-sync-schedule", + task_name="my_plugin.app.tasks.sync", + task_kwargs={"remote_pk": str(remote.pk), "optimize": True}, + dispatch_interval=timedelta(hours=6), +).save() +``` + +The args and kwargs stored in `task_args` and `task_kwargs` are passed directly +to `dispatch()` when the schedule fires, so they should match the signature of +the task function referenced by `task_name`. Both fields are encrypted at rest +(they will not be included in API responses). diff --git a/pulpcore/app/migrations/0150_taskschedule_task_kwargs.py b/pulpcore/app/migrations/0150_taskschedule_task_kwargs.py new file mode 100644 index 00000000000..3dffacd3466 --- /dev/null +++ b/pulpcore/app/migrations/0150_taskschedule_task_kwargs.py @@ -0,0 +1,24 @@ +# Generated manually + +from django.db import migrations + +import pulpcore.app.models.fields + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0149_distributedpublication"), + ] + + operations = [ + migrations.AddField( + model_name="taskschedule", + name="task_args", + field=pulpcore.app.models.fields.EncryptedJSONField(default=list), + ), + migrations.AddField( + model_name="taskschedule", + name="task_kwargs", + field=pulpcore.app.models.fields.EncryptedJSONField(default=dict), + ), + ] diff --git a/pulpcore/app/models/task.py b/pulpcore/app/models/task.py index f93a21972a1..924f360ff90 100644 --- a/pulpcore/app/models/task.py +++ b/pulpcore/app/models/task.py @@ -443,6 +443,8 @@ class TaskSchedule(BaseModel): next_dispatch = models.DateTimeField(default=timezone.now, null=True) dispatch_interval = models.DurationField(null=True) task_name = models.TextField() + task_args = EncryptedJSONField(default=list) + task_kwargs = EncryptedJSONField(default=dict) last_task = models.ForeignKey(Task, null=True, on_delete=models.SET_NULL) class Meta: diff --git a/pulpcore/plugin/models/__init__.py b/pulpcore/plugin/models/__init__.py index d8d936707f1..5e0a3c55ad3 100644 --- a/pulpcore/plugin/models/__init__.py +++ b/pulpcore/plugin/models/__init__.py @@ -38,6 +38,7 @@ SigningService, Task, TaskGroup, + TaskSchedule, Upload, UploadChunk, VulnerabilityReport, @@ -84,6 +85,7 @@ "SigningService", "Task", "TaskGroup", + "TaskSchedule", "Upload", "UploadChunk", "EncryptedTextField", diff --git a/pulpcore/plugin/serializers/__init__.py b/pulpcore/plugin/serializers/__init__.py index cbc95e7336b..5380e583054 100644 --- a/pulpcore/plugin/serializers/__init__.py +++ b/pulpcore/plugin/serializers/__init__.py @@ -38,6 +38,7 @@ SingleArtifactContentSerializer, SingleContentArtifactField, TaskGroupOperationResponseSerializer, + TaskScheduleSerializer, RepositoryAddRemoveContentSerializer, ValidateFieldsMixin, validate_unknown_fields, @@ -89,6 +90,7 @@ "SingleArtifactContentSerializer", "SingleContentArtifactField", "TaskGroupOperationResponseSerializer", + "TaskScheduleSerializer", "RepositoryAddRemoveContentSerializer", "ValidateFieldsMixin", "validate_unknown_fields", diff --git a/pulpcore/tasking/_util.py b/pulpcore/tasking/_util.py index 8816d1c2422..6fb2dcf3395 100644 --- a/pulpcore/tasking/_util.py +++ b/pulpcore/tasking/_util.py @@ -300,6 +300,8 @@ def dispatch_scheduled_tasks(): with transaction.atomic(): task_schedule.last_task = dispatch( task_schedule.task_name, + args=task_schedule.task_args, + kwargs=task_schedule.task_kwargs, ) task_schedule.save(update_fields=["next_dispatch", "last_task"])