Pulp plugin for managing task schedules via CRUD API
Project description
pulp-workflow
Warning: This is a community plugin and is not officially supported. Scheduling tasks incorrectly can cause serious issues in your Pulp instance. Always test in a development environment first before applying changes to production.
A Pulp plugin that introduces the Workflow model. Workflows build on top of
tasks in Pulp allowing users to:
- Schedule tasks to run at any given time
- Run sequences of tasks in a specific order
- Set up callback services to run on workflow lifecycle events (e.g. running, completed, failed, canceled, finished)
A Workflow owns one or more WorkflowTask rows. Each task records the
task_name, task_args, task_kwargs, and any reserved_resources to use
when dispatching it. Workflows are immutable after creation: to change a
workflow, cancel it (if it has not yet started) and create a new one.
Endpoints
| Method | URL | Description |
|---|---|---|
| GET | /pulp/api/v3/workflow/workflows/ |
List workflows |
| POST | /pulp/api/v3/workflow/workflows/ |
Create a workflow (with tasks) |
| GET | /pulp/api/v3/workflow/workflows/<pk>/ |
Retrieve a workflow |
| PATCH | /pulp/api/v3/workflow/workflows/<pk>/ |
Cancel a workflow (body: {"state": "canceled"}). Works whether the workflow is waiting or running; returns 409 only if the workflow is already in a terminal state. Only "canceled" is accepted as the target state. |
How execution works
When a workflow is created, TaskSchedule dispatches a single execute_workflow
task. Rather than looping inside one long-running task (which would pin a
worker for the entire duration of the pipeline), execute_workflow runs one
step at a time and re-dispatches itself for the next step. Each invocation
either transitions the workflow to running (on the first step) or inspects
the previous step's child task and fails the workflow if it did not complete.
If there are no more WorkflowTask rows at the next index, the workflow is
marked completed.
Sequencing relies on pulpcore's tasking locks rather than polling. Every
invocation dispatches the child task with a shared lock on the workflow's
resource string (pulp_workflow:workflow:<pk>) and then dispatches the next
execute_workflow continuation with an exclusive lock on the same
resource. Because the exclusive lock cannot be granted while the shared lock
is held, the continuation is guaranteed to wait until the child task ends —
without blocking a worker on a polling loop. This keeps concurrent workflows
from deadlocking when their count meets or exceeds the worker count.
The diagram below shows two consecutive tasks. S denotes a shared lock and
X denotes an exclusive lock on the workflow resource.
sequenceDiagram
autonumber
participant TaskSchedule
participant EW0 as execute_workflow(0)
participant T0 as Child Task 0
participant EW1 as execute_workflow(1)
participant T1 as Child Task 1
participant EW2 as execute_workflow(2)
TaskSchedule->>EW0: dispatch (X on workflow)
activate EW0
EW0->>EW0: state = RUNNING
EW0->>T0: dispatch (S on workflow)
EW0->>EW1: dispatch (X on workflow) — queued
deactivate EW0
activate T0
Note over EW1: blocked: X waits for S to release
T0-->>T0: run task body
T0->>T0: state = COMPLETED
deactivate T0
activate EW1
EW1->>EW1: verify Task 0 COMPLETED
EW1->>T1: dispatch (S on workflow)
EW1->>EW2: dispatch (X on workflow) — queued
deactivate EW1
activate T1
Note over EW2: blocked until T1 finishes
T1-->>T1: run task body
T1->>T1: state = COMPLETED
deactivate T1
activate EW2
EW2->>EW2: verify Task 1 COMPLETED
EW2->>EW2: no task at index 2 → state = COMPLETED
deactivate EW2
If any child task ends in a non-completed state, or if dispatching a child
raises, the next execute_workflow invocation records the failure on the
workflow (error field, including the child's traceback when available),
transitions the workflow to failed, and stops the chain.
Task groups
Every workflow is backed by a pulpcore TaskGroup. On creation, the workflow
allocates a TaskGroup(description="Workflow: <name>") in the workflow's
domain and links it via the task_group field on the Workflow resource. The
dispatched child tasks and the execute_workflow continuations are members
of that group. The initial execute_workflow task itself is dispatched by
the TaskSchedule created at workflow-create time and is not a member of
the group. Membership means:
GET /pulp/api/v3/task-groups/<pk>/lists every task the workflow has spawned in one place.GET /pulp/api/v3/tasks/?task_group=<pk>filters tasks to that workflow.- Existing client tooling (
monitor_task_group,TaskGroupOperationResponse) works against workflows the same way it does for replication and pulp-import. - A child task can discover that it is part of a workflow via
TaskGroup.current()withoutpulp_workflowhaving to plumb that context through itself.
The group's all_tasks_dispatched flag is False while the workflow is
running and flipped to True exactly once the workflow reaches a terminal
state (completed, failed, or canceled).
Cancellation
A workflow can be canceled either by PATCHing the workflow with
{"state": "canceled"} or by canceling its backing TaskGroup directly.
Both paths converge on the same terminal state: Workflow.state = canceled,
finished_at set, TaskGroup.all_tasks_dispatched = True, and any
in-flight or queued child tasks (including the execute_workflow
continuation) canceled. PATCH on an already-terminal workflow returns 409.
The TaskGroup cancel path is bridged back to the workflow row via a
post_save receiver on TaskGroup, so cancellation initiated outside the
workflow viewset still terminates the Workflow correctly.
flowchart TD
A[PATCH /pulp/api/v3/workflow/workflows/<pk>/<br/>state: canceled] --> B[WorkflowViewSet]
B --> C[Workflow.state = canceled<br/>finished_at = now]
C --> D[cancel_task_group<br/>on commit]
E[POST /pulp/api/v3/task-groups/<pk>/cancel/] --> F[pulpcore cancels<br/>group's tasks]
F --> G[TaskGroup.all_tasks_dispatched = True<br/>TaskGroup.save]
D --> G
G --> H[post_save receiver<br/>on TaskGroup]
H --> I{Workflow already<br/>terminal?}
I -- yes --> J[no-op]
I -- no --> K[Workflow.state = canceled<br/>finished_at = now]
classDef terminal fill:#e8f5e9,stroke:#2e7d32;
class C,K terminal;
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pulp_workflow-0.1.1.tar.gz.
File metadata
- Download URL: pulp_workflow-0.1.1.tar.gz
- Upload date:
- Size: 36.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d840522ca335b229364e146ba19d06b0781640a2f9d47c55afe144697bc186e1
|
|
| MD5 |
f4970882a7d407ab051327104e8fa3fc
|
|
| BLAKE2b-256 |
6dc02182d7771a5ff88b711ef11018d6104fae0b893a4a9a4a7b170c3b70da47
|
Provenance
The following attestation bundles were made for pulp_workflow-0.1.1.tar.gz:
Publisher:
publish.yml on daviddavis/pulp_workflow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulp_workflow-0.1.1.tar.gz -
Subject digest:
d840522ca335b229364e146ba19d06b0781640a2f9d47c55afe144697bc186e1 - Sigstore transparency entry: 1757144718
- Sigstore integration time:
-
Permalink:
daviddavis/pulp_workflow@2365e7bc0c770a18789b3272287b917051fd0c5e -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/daviddavis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2365e7bc0c770a18789b3272287b917051fd0c5e -
Trigger Event:
push
-
Statement type:
File details
Details for the file pulp_workflow-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pulp_workflow-0.1.1-py3-none-any.whl
- Upload date:
- Size: 41.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d058a58257a87040bb94f7984cb2ea815f28e5f867e3682bd3c71340b19036af
|
|
| MD5 |
1c2fdb8ede5f2ac272cbe62d5c3867e7
|
|
| BLAKE2b-256 |
369207eae624dc8d53541d6408d5eb4fbba26e72a8872f8d4b89b36f0b252336
|
Provenance
The following attestation bundles were made for pulp_workflow-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on daviddavis/pulp_workflow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pulp_workflow-0.1.1-py3-none-any.whl -
Subject digest:
d058a58257a87040bb94f7984cb2ea815f28e5f867e3682bd3c71340b19036af - Sigstore transparency entry: 1757144789
- Sigstore integration time:
-
Permalink:
daviddavis/pulp_workflow@2365e7bc0c770a18789b3272287b917051fd0c5e -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/daviddavis
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2365e7bc0c770a18789b3272287b917051fd0c5e -
Trigger Event:
push
-
Statement type: