MLOps
Pipeline Design and Orchestration
Design observable, testable workflows whose steps, artifacts, retries, parameters, and ownership are explicit.
By the end you can
- Decompose an ML workflow into tasks with clear inputs, outputs, and side effects
- Distinguish orchestration state from the state of external systems
- Choose retry, timeout, concurrency, and dependency policies deliberately
- Use orchestration metadata to support recovery and investigation rather than hide complexity
Example
A retry deploys the same candidate twice
A promotion task moves an alias, then times out before it can report success. The alias has already moved. The orchestrator's record of the attempt is not a record of what changed outside it.
The largest published version of that failure was written up by the company it happened to. AWS's summary of the 19-20 October 2025 disruption in the Northern Virginia (US-EAST-1) Region describes a delayed actor overwriting newer external state, and then a piece of automation removing what it had just written.
- First attempt: The registry accepts the alias change, so the external system is already in its new state.
- Timeout: The orchestrator receives no completion response. Its record of the task now disagrees with the world it was supposed to be changing.
- The same failure, documented: In AWS's own post-event summary, a delayed DNS Enactor applied a stale plan over a newer one, and the cleanup process then deleted it, leaving an empty DNS record for dynamodb.us-east-1.amazonaws.com.
- Downstream effect: No automation could put the record back. AWS records that the empty record “ultimately required manual operator intervention to correct”.
- Required design: Use an idempotency key and reconcile the external state before retrying. The rule is standardised, not a preference. RFC 9110 marks PUT, DELETE and the safe methods as idempotent, and it tells clients when to stop: “A client SHOULD NOT automatically retry a request with a non-idempotent method unless it has some means to know that the request semantics are actually idempotent, regardless of the method, or some means to detect that the original request was never applied.”
A green DAG can produce a bad release
On 4 October 2020 Public Health England published a statement about the previous week's COVID-19 case counts. The automated transfer had run. The output was silently short.
“A technical issue was identified overnight on Friday 2 October in the data load process that transfers COVID-19 positive lab results into reporting dashboards. After rapid investigation, we have identified that 15,841 cases between 25 September and 2 October were not included in the reported daily COVID-19 cases.” — Michael Brodie, Interim Chief Executive of Public Health England, 4 October 2020.
Over 75% of the missing records — 11,968 of the 15,841 — fell in the three days from 30 September to 2 October. Every individual still received their test result normally. What failed was the load into the reporting dashboards, and with it contact tracing, which waited until the backlog was transferred by 1am on 3 October. The pipeline did not crash. It reported success and published a number that was 15,841 cases wrong.
Orchestration proves that declared tasks followed declared transitions. It does not prove that the workflow modeled the right dependencies, or that external side effects were safe.
Visual
Control plane and data plane state
The orchestrator sees only part of the workflow reality. Workflow state is task dependencies, attempts, scheduling, timeout, and completion status. Artifact state is the datasets, models, reports, images, and manifests that tasks produce. External system state is warehouse commits, registry records, aliases, tickets, and traffic routes. Decision state is approvals, exceptions, release conditions, and rollback intent. Only the first of those four lives inside the scheduler.
The separation is not academic. In the October 2025 US-EAST-1 event the data plane stayed healthy while the control plane failed, and AWS says so directly: “Existing EC2 instances that had been launched prior to the start of the event remained healthy and did not experience any impact for the duration of the event.” What broke was the ability to change anything. New launches failed from 11:48 PM PDT on 19 October until full EC2 recovery at 1:50 PM PDT on 20 October. A workflow that only watches its own control plane cannot tell those two situations apart.
- 01
Workflow state
Task dependencies, attempts, scheduling, timeout, and completion status.
- 02
Artifact state
Datasets, models, reports, images, and manifests produced by tasks.
- 03
External system state
Warehouse commits, registry records, aliases, tickets, and traffic routes.
- 04
Decision state
Approvals, exceptions, release conditions, and rollback intent.
Comparison
Dependency, trigger, and condition are not synonyms
A DAG becomes misleading when every relationship is drawn as a simple arrow. Three different things then look identical.
A data dependency means a task needs a specific artifact produced upstream. Its identity should be explicit. It supports caching and replay, and it can be validated before execution — evaluate model digest M on dataset snapshot D.
A control dependency means a task must wait for an event or an approval. It may transfer no data at all. It represents ordering or authority, and it needs a timeout and an escalation path — publish only after risk approval.
A conditional branch means the next task depends on observed evidence. It requires a recorded predicate, it must handle every outcome, and it can create selection bias — promote only if slice and latency gates pass.
Drawn identically, the three become indistinguishable in a diagram. The review question each one demands — which artifact, whose authority, what predicate, recorded where — stops being asked.
Data dependency
A task needs a specific artifact produced upstream.
- Identity should be explicit
- Supports caching and replay
- Can be validated before execution
- Example: evaluate model digest M on dataset snapshot D
Control dependency
A task must wait for an event or approval.
- May not transfer data
- Represents ordering or authority
- Needs timeout and escalation
- Example: publish only after risk approval
Conditional branch
The next task depends on observed evidence.
- Requires recorded predicate
- Must handle all outcomes
- Can create selection bias
- Example: promote only if slice and latency gates pass
Tasks should expose artifacts and side effects
A task boundary is useful when its inputs and outputs can be named, inspected, cached, retried, and owned. Hidden reads from mutable tables or configuration services do the opposite. They make the DAG look simpler while weakening reproducibility.
Side effects require extra care. Writing a registry entry, sending a notification, or switching traffic is not equivalent to producing an immutable dataset partition. Retry semantics must reflect that difference.
The code around the model has been measured. In 2015 D. Sculley and nine colleagues put a ratio on it: “Because a mature system might end up being (at most) 5% machine learning code and (at least) 95% glue code, it may be less costly to create a clean native solution rather than re-use a generic package.” The same sentence had appeared in their own workshop paper the year before. The ratio is an argument about where boundaries belong, not a number anyone should copy onto a slide about their own pipeline. Most of what an orchestrator coordinates is not the model. It never was.
Steps
Design a task contract
Use the contract for each task before connecting the DAG: name inputs and outputs with immutable identities and declared schemas; declare every external write, alias move, message, and ticket; define retry semantics — idempotency, reconciliation, backoff, maximum attempts; emit task state, artifact identity, timing, resource use, and failure reason; and document how to resume, skip, compensate, or rebuild the task.
Two independent organisations publish that contract in their own documentation, and both derive it from the retry. Airflow's best-practices page begins there: “Airflow can retry a task if it fails. Thus, the tasks should produce the same outcome on every re-run.” It then makes the rule concrete. An INSERT during a re-run “might lead to duplicate rows in your database”, so replace it with UPSERT. On the input side: “Read and write in a specific partition. Never read the latest available data in a task.”
Google's Cloud Composer documentation states the granularity rule independently: “Each task should be an idempotent unit of work. Consequently, you should avoid encapsulating a multi-step workflow within a single task, such as a complex program running in a PythonOperator.” Between them the two documents name the two ways a task contract is usually broken. A task that reads whatever is newest. A task that hides a multi-step workflow behind one name.
1. Name inputs and outputs
Use immutable identities and declared schemas where possible.
2. Declare side effects
List every external write, alias move, message, and ticket.
3. Define retry semantics
Choose idempotency, reconciliation, backoff, and maximum attempts.
4. Set observability
Emit task state, artifact identity, timing, resource use, and failure reason.
5. Assign recovery ownership
Document how to resume, skip, compensate, or rebuild the task.
Analogy
The cue was called, and the door was still locked
A stage manager calls cues for lighting, sound, scenery, and performers, and every cue can land exactly on time. A prop can still be missing. A door can still be locked. Coordination state is not the same as physical state.
On 1 August 2012 the door really was locked. Knight Capital deployed new SMARS router code to its production servers. It reached seven of the eight. The SEC's order records what nobody caught: “During the deployment of the new code, however, one of Knight's technicians did not copy the new code to one of the eight SMARS computer servers. Knight did not have a second technician review this deployment and no one at Knight realized that the Power Peg code had not been removed from the eighth server, nor the new RLP code added.” The eighth server still held the retired Power Peg code, and the repurposed flag activated it. In about 45 minutes it produced over 4 million executions in 154 stocks for more than 397 million shares, and a loss of over $460 million. The SEC censured Knight and ordered a $12,000,000 civil penalty on 16 October 2013.
Nobody in a theatre repeats a cue thirty times in four seconds. Software tasks are retried automatically, and a retry can duplicate a side effect that nothing will undo. That is why idempotency and external-state reconciliation have to be designed rather than assumed.
A scheduler knows which cue it issued; the system must still verify what actually changed.
Key idea
Orchestration can centralize failure
A highly coupled DAG may require one platform, metadata store, and scheduler for every step. An outage or an incompatible upgrade can then stop training, evaluation, and recovery at the same time.
The retry that centralisation makes uniform is itself a measured failure class. It has a name, metastable failure, given to it in 2021 by Bronson and three colleagues, who also named the mechanism: “One of the most common failure-sustaining mechanisms is request retries. Retrying failed requests is widely used to mask transient issues. However, it also results in work amplification, which can lead to additional failures.” In 2022 Huang and colleagues counted them: 22 metastable failures from 11 organisations, and at least 4 of the 15 major AWS outages of the previous decade. The October 2025 US-EAST-1 summary uses the same vocabulary. AWS writes that DWFM “had entered a state of congestive collapse”, and that “this situation had no established operational recovery procedure”.
One control plane can also fail everywhere at once. On 12 June 2025 a quota policy update did that to Google Cloud, from 10:51 to 18:18 US/Pacific. Google's own incident report reconstructs it: “Given the global nature of quota management, this metadata was replicated globally within seconds. This policy data contained unintended blank fields. Service Control, then regionally exercised quota checks on policies in each regional datastore. This pulled in blank fields for this respective policy change and exercised the code path that hit the null pointer causing the binaries to go into a crash loop.” The red-button rollout completed within 40 minutes. us-central1 took roughly 2 hours 40 minutes. Cloudflare, a separate company, lost 90.22% of Workers KV requests for 2 hours 28 minutes because of it.
Design control-plane resilience, exportable metadata, manual recovery procedures, and bounded dependencies. The orchestrator should coordinate the workflow, not become the only place where its meaning exists.
A workflow is operable when its state can be understood and recovered outside the happy-path scheduler.
Prefer inspectable boundaries over impressive DAGs
A pipeline diagram should make the workflow easier to reason about. If it hides mutable reads, external effects, or manual decisions behind generic task names, it is decorative.
Review one failed run from the artifact graph outward: what existed, what changed, what was retried, and what recovery remains safe?
The same 2015 paper names the shape a decorative DAG takes. It calls it a pipeline jungle. “As a special case of glue code, pipeline jungles often appear in data preparation. These can evolve organically, as new signals are identified and new information sources added incrementally. Without care, the resulting system for preparing data in an ML-friendly format may become a jungle of scrapes, joins, and sampling steps, often with intermediate files output.” Evolve, not grow: nobody designs a jungle. It arrives one reasonable addition at a time, each of them locally defensible, and the DAG that draws it looks busy and healthy the whole way.
Key takeaways
- A green DAG proves task transitions, not the correctness of the released system: Public Health England's transfer ran, and the reported figures were still short 15,841 cases.
- Task contracts should expose immutable artifacts and every external side effect, because Airflow's own rule is that a task must “produce the same outcome on every re-run”.
- Data dependencies, control dependencies, and conditional branches carry different semantics and must not be drawn as one arrow.
- Retries require idempotency or reconciliation when tasks change external state. RFC 9110 states the condition, and the metastable-failure literature names retries as the most common failure-sustaining mechanism.
- Orchestration metadata should support recovery outside the happy path: AWS's October 2025 empty DNS record “ultimately required manual operator intervention to correct”.
- The best pipeline boundary is inspectable, testable, recoverable, and owned — one bad global config record put Google's Service Control binaries into a crash loop in every region.