The run timeline
There are two reasons anyone opens a run. It failed, or it took too long. The executions view answers the first one: which step failed, what it said, where it sits on the graph. The timeline answers the second.
Open a run and its steps are a list of bars on one clock, running from the moment the first step started to the moment the last one finished. One row per step, carrying that step’s phase, its bar, its duration, what it spent queueing, and its share of the run.
The split that does the work
Section titled “The split that does the work”Argo starts a node’s clock when it creates the node, not when the container starts. A step’s wall clock is therefore two things stuck together: the wait for a pod, and the work. As one number they are indistinguishable, and a step waiting twenty minutes for a GPU reads exactly like a step computing for twenty minutes.
The connector reports the container’s own start off the pod, alongside the node’s,
and each bar is divided there. The queue is drawn inside the bar and the row says
how long it was: 3m12s queued, or no queue for a step that started at once.
A third state matters as much as the other two. Where no container start arrived,
the row says queue not measured and the bar stays whole. That covers a pod that
is gone, a step that never ran, and a timestamp the node’s own clock contradicts.
“We watched and there was no wait” and “nobody told us” draw the same plain bar,
so the words have to separate them, and a skewed timestamp is left out rather than
clamped into range to manufacture a gap.
None of this needs anything switched on. The node timestamps ride along with the run status the connector already reports, and the container start is one read of the pod it already has.
The pod behind a step
Section titled “The pod behind a step”Argo puts more than your container in the pod. On the default layout an init
container stages the template, the script and any input artifacts before your
container starts, and a wait container collects the outputs afterwards. Your
container is the one named main.
dagweave reads main and nothing else: its requests and limits, when it started,
and its logs. The rest of the pod is Argo’s own machinery, and no number on this
page counts containers or depends on how many there are.
Argo 4.1 adds a second layout that drops the init container. A supervisor
container runs alongside main and takes both jobs, the staging before and the
collecting after. Init containers you put on the step yourself are untouched and
still run first.
The layout is beta and off by default. A cluster operator turns it on with
initlessPod.enabled on the workflow controller. It also needs Kubernetes image
volumes, which are behind a feature gate before 1.36 and absent before 1.33.
Two things follow for this page. The pod carries one container fewer, so a step
that misbehaves has one less place to look. And main is no longer held behind a
container that has to finish first, so pulling the step’s image and staging its
inputs overlap instead of happening one after the other.
That moves the split. On the default layout, input artifacts are staged before
main starts, and the time goes to the queue. On the init-less layout they are
staged while main is already up, and the time goes to the work. A step that
loads artifacts therefore reads differently on the two layouts, and its queue
number is not comparable across them.
Two orders
Section titled “Two orders”The rows sort two ways, and it is one list either way rather than a chart with a table underneath it.
Run order follows the order the run reached the steps, so the list keeps the shape of the DAG and parallel siblings hold their places. Duration puts the longest first, which is the readable answer on a DAG too wide to take in as a waterfall.
Switching re-stacks the rows and moves no bar. Offsets and widths are computed off the run’s window, never off the row order, so the clock stays put while the reading order changes. Each row also carries its percentage of the run.
A run, read end to end
Section titled “A run, read end to end”Take nightly-feature-build, four steps in a line, 41m12s.
Sorted by duration, build-features is on top at 33m47s, 82% of the run. Then
train-model at 4m30s, publish-metrics at 1m51s, fetch-orders at 1m04s.
Training is the part that sounds expensive and is eleven percent of it.
The finding is inside the top bar. Its row reads 32m14s queued, and the queue
segment fills most of the bar’s width. That step is not slow. It spent about
ninety seconds working and half an hour waiting for a node with a GPU on it, and
nothing you change inside the step will move the run’s duration.
What draws a row, and what does not
Section titled “What draws a row, and what does not”Argo’s orchestration root is dropped. It has no pod, so it has no logs and no time of its own, and leaving it in made the obvious first click the one that returned nothing.
Everything with a pod behind it gets a row, and the list is flat:
- Each retry attempt. Argo records an attempt as a node in its own right, so a step that came good on the third try contributes three rows, two of them failed.
- Each item of a fan-out.
withParam,withItemsandwithSequenceproduce one node per item, and a thousand items are a thousand rows. There is no grouping under the parent step and nothing to expand. - Every step of a nested workflow, at the same level as the rest. Nesting on the canvas does not nest here.
A step the connector reported no start for has no place on the clock. It draws no
bar, reads no timing reported, and sits below the rows that do.
Opening a row
Section titled “Opening a row”Click a row and it expands to what is known about that step: why it is waiting if
it is, the message Argo left on the node, its requested and actual resources, its
trace link, and its logs, fetched on first open. Logs come from the container
named main, with a toggle for the rest of the pod.
On a failed run the failing step’s row is already open when the view is, so you land on the output that explains the failure instead of hunting for it.
The canvas is a separate surface. During a live run dagweave tints each node on the graph by its phase and pulls focus to a failure; the timeline lives in the run detail view, which you reach from the run history or from the Logs button on that live rail. Clicking a bar opens the step, it does not move the canvas.
When a bar is still open
Section titled “When a bar is still open”A step with no finish time has its bar drawn open on the right, growing about once
a second, and its share column reads so far instead of a percentage that would
be wrong the moment it was printed. The run’s window ends at now while anything is
still going, so every bar is measured against the same live clock.
If a bar stays open longer than it should, the question stops being “where did the time go” and becomes “why is nothing happening”, which is a different page: why a run is not moving.
The finer breakdown
Section titled “The finer breakdown”The timeline splits a run into steps and a step into queue and work. To go underneath that, follow a trace link.
Argo’s controller and executor emit OpenTelemetry spans for the machinery beneath each node: creating the pod, acquiring a lock, loading and saving artifacts, saving logs. The timeline draws none of that. What it gives you is the link. every expanded step carries View trace, and the run header carries Trace for the workflow as a whole, each pointing into your own Jaeger or Tempo.
Both need two things to be true. The workflow controller has to be exporting
spans, which it starts doing once OTEL_EXPORTER_OTLP_TRACES_ENDPOINT in its
environment points at your collector. And the ArgoConnection has to carry
traceURLTemplate and workflowTraceURLTemplate, the URL shapes of your backend.
A run with no links says which of the two is missing rather than leaving a blank.