Parallelise bundle publishing
Table of Contents
This page is a capture in the inbox bucket of the product backlog — a pre-sprint idea, not yet pulled into a sprint as a story.
1. What
A bundle is published one workflow step per dataset, and the steps are chained so that each waits for the one before it. Most of those datasets are independent of one another, so most of that waiting buys nothing. The chain should say which datasets actually read another dataset, and the rest should publish together.
2. Why
Measured on a tenant bootstrap from the acme_demo profile, 2026-10-08, bright
faraday:
| step | ran for |
|---|---|
| system_provision | ~1s |
| publish_bundle | 2m 14s |
| import_lei_hierarchy | ~0s |
| provision_party | ~4s |
| load_staff | ~7s |
| attach_photos | ~11s |
| start_market_feeds | beside the party chain |
| complete_provisioning | ~4s |
The run took 2m 41s end to end, so publish_bundle is about 83% of a
bootstrap's wall clock, and it is now the only thing between a bootstrap and
being quick. The engine already runs independent steps together – the same
change that lets start_market_feeds run beside import_lei_hierarchy – so the
work here is not in the engine. It is in saying what a dataset depends on.
The chaining is deliberate and conservative rather than an oversight. When the
engine became a graph, a chain whose steps declare nothing runs flat, so
bundle_publish_workflow now declares that each dataset reads the one before it.
That was the only statement of dependency available and it preserved the order
that the ordinal used to carry. It is a placeholder for a real answer, not the
answer.
3. Open questions
- Where does the dependency live? It is a fact about the datasets, and the datasets are DQ rows, so it could be a relation between them, a field on the dataset, or derived from what each publisher writes. Choosing this is the actual work.
- Is publishing two datasets at once safe for the target tables? Reference data has foreign keys between its tables, so a dataset that writes a child table may need its parent's rows to exist first even where it does not read the parent's dataset. Reading and depending are not the same relation.
- What happens when one of a parallel batch fails? Compensation order is derived from the graph's topological order, so a batch that fails part-way must still roll back in an order that respects the real dependencies.
4. References
projects/ores.dq/api/include/ores.dq.api/workflow/bundle_publish_workflow.hpp– one step per dataset, and where the order is declared today.projects/ores.workflow/core/include/ores.workflow.core/service/workflow_graph.hpp– the graph the engine dispatches from.projects/ores.iam/api/include/ores.iam.api/workflow/provision_tenant_workflow.hpp– the kind-to-kind dependency statement, and the walk-back that answers a need the run did not order. The pattern to copy if a bundle's dependency is declared per dataset.doc/agile/versions/v0/sprint_27/gather-a-runs-inputs-by-declared-dependency/task_hold-a-workflow-as-a-dependency-graph.org– the task that made a run's chain a graph, and its measurements.
5. See also
- Model the workflow payloads instead of storing them as documents – the other open question about this schema.