6.6.3 Measuring Build-Service Latency and Reliability
A dashboard can report that the remote executor is busy while developers still wait on cache lookup, queueing, output download, or an incomplete result stream. A Bazel-aware service-level indicator (SLI) turns one of those observations into a precisely defined measurement: it names the journey, lifecycle interval, population, denominator, missing-data rule, and service layer that can act on it.
6.6.1 Tracing a Build Across Services supplies the identities and joins needed to follow one invocation across services. An SLI aggregates those correlated observations without erasing where they came from. This is different from the controlled before-and-after experiments in 6.1.2 Measuring Builds Fairly: an experiment tests a change, while an operational SLI continuously describes a bounded user outcome or service transition.
Start With the Outcome, Not the Available Counter
The easiest metrics to collect are often component metrics: executor CPU, scheduler memory, cache storage occupancy, RPC request rate. They are useful for operating those components, but none directly states how long a developer waited or whether CI produced a complete result.
Start with a question that has one observable answer:
- How long did an interactive invocation take from request acceptance to usable top-level outputs?
- How long did an eligible remote action wait between admission and assignment to a compatible worker?
- What fraction of eligible cache lookups returned a usable result whose referenced content was available?
- What fraction of required presubmit results became available to the result consumer before the workflow deadline?
Bazel provides several evidence surfaces rather than one universal metrics stream. BEP, trace profiles, execution logs with spawn metrics, and execution graph logs answer different questions about an invocation and its actions.1 The JSON trace profile, for example, exposes phase-level context and the action critical path, while execution evidence can separate remote setup or fetching from process time.2 A service SLI may join these with scheduler, cache, executor, CI, and result-consumer telemetry, but it must preserve the meaning of each boundary.
Write the Indicator as a Contract
An SLI specification should be reviewable without opening its dashboard. Use a compact contract with these labelled fields:
- Outcome: The user-visible result or service transition being measured.
- Population: Journey and cohort dimensions: revision class, target scope, configuration, platform, cache state, action class, and relevant versions.
- Start and end: Named correlated events, including which clock or duration source defines the interval.
- Numerator: Observations satisfying the stated condition.
- Denominator: All observations eligible for that condition, including the fate of partial observations.
- Exclusions: Explicitly justified cases, recorded separately rather than silently dropped.
- Missing data: How absent starts, ends, joins, or required results change the indicator and its validity.
- Owner: The layer able to investigate or change the measured transition.
Here is a complete queue-latency contract for one deliberately narrow cohort. It is an inspectable design fixture, not captured production telemetry: the full contract and its three evidence cases make the boundary executable.
The filled contract is one vertical record:
- Outcome and population: A
CppCompileaction in a presubmit reaches thelinux-compilepool; the cohort pins Linux x86_64, client 9.1.0, and executor imagecompile-v4. - Start and end:
scheduler.admission.acceptedthroughscheduler.assignment.recorded, joined by(invocation_id, action_digest). - Numerator and denominator: Count eligible joined assignments at most 60 seconds in the numerator; retain all eligible admissions in that cohort in the denominator.
- Missing-data rule: A cancelled action is reported separately. An action
still unmatched when the window closes is
incomplete; a missing trustworthy join isinvalid. Neither becomes a short queue sample. - Validity and owner: Publish incomplete and invalid counts beside the
percentile. The scheduler and
linux-compilepool own the transition.
Consider a remote-action queue-latency indicator. Its population is not “all remote actions.” It could be compile actions admitted to one compatible Linux pool for interactive invocations under a specified client and executor-image cohort. Its interval begins at accepted admission and ends at worker assignment. Actions rejected before admission, cancelled by the client, unmatched because no compatible pool exists, or missing one boundary need explicit dispositions. If they simply disappear from the dataset, the remaining percentile becomes faster precisely when the system loses difficult work.
The same discipline applies to ratios. A cache reuse indicator needs a denominator of eligible lookups, not total actions. Its numerator must mean a usable result, not merely an Action Cache metadata response when referenced content cannot be materialized. A result-completeness indicator needs the set of required results as its denominator; counting only events that arrived makes delivery loss invisible.
Compare: Two dashboards report remote queue latency. One includes only actions that reached a worker. The other retains admitted actions that were cancelled or still unmatched and reports their disposition separately. Which one can support a reliability decision?
Reveal
The second. The first conditions on eventual worker assignment, so it can look healthy while actions wait indefinitely or vanish before assignment. The second preserves the eligible population and makes incomplete observations visible; its latency distribution and its completion or disposition ratio can be interpreted together.
Separate a Journey From Its Stages
Keep at least one end-to-end indicator for each protected journey. An interactive edit-build loop, presubmit, postsubmit, and release build have different start events, required outputs, and tolerable failure modes. A single “build duration” distribution mixes those contracts and can move merely because the workload mixture changed.
Then define stage indicators that can explain the journey:
A protected presubmit journey is measured from request to usable required result. Cache lookup, input transfer, queueing, execution, output transfer, and result delivery explain the journey. A missing start, end, or trustworthy join becomes incomplete or invalid evidence rather than a fast latency record. Bounded dimensions remain in metrics while invocation and action identities remain in trace records.
| Stage | Example interval or ratio | Likely owning layer |
|---|---|---|
| Cache lookup | lookup request to usable hit, plus miss and incomplete-result dispositions | cache client and backend |
| Input transfer | missing-input discovery through confirmed availability | client, CAS, and network path |
| Queueing | admitted action through compatible worker assignment | scheduler and pool topology |
| Execution | worker start through completed process result | executor and action implementation |
| Output transfer | produced output through required materialization | executor, CAS, client, and network path |
| Result delivery | generated required result through acknowledged consumer availability | Bazel, BES, and consumer |
| Developer wait | journey request through usable outcome | the end-to-end service owner |
Invocation tooling demonstrates why this decomposition matters: a successful build can break a long action into input fetch, queue wait, process execution, and output upload rather than presenting one anonymous remote duration.3 Historical build analysis also becomes more useful when operators can select a slow cohort and compare its dimensions with the baseline instead of treating a high percentile as an explanation.4
Stage indicators are diagnostic evidence, not competing definitions of the user outcome. Lower execution latency does not establish a faster journey if queueing or materialization grew. Higher executor utilization is neither a latency improvement nor a reliability result. Use utilization to form a capacity hypothesis, then test it against the relevant queue, throughput, and end-to-end indicators.
Keep Cohorts Comparable Without Exploding Cardinality
Percentiles are meaningful only for a named population. Partition by a dimension when it changes the service path or leads to a different operational decision: journey, target or action class, target and execution platform, compatible pool, cache outcome, client/backend version, or result requirement. Long-term build analysis can expose regressions by selecting slow invocations and finding dimensions disproportionately represented in them.4
Do not promote every label, target, digest, user, or invocation ID to a metric dimension. Those identities are valuable for drilling from an aggregate into a trace, but unbounded dimensions make metric storage costly and dashboards hard to interpret. Keep bounded cohort dimensions in the metrics system; retain high-cardinality identities in trace or event storage with suitable access and retention controls.
When a cohort changes, report that change rather than presenting the new distribution as continuous with the old one. A shift from warm developer servers to fresh CI clients, a new executor image, or a different target mix can move the indicator without any service regression. 6.1.2 Measuring Builds Fairly shows how to construct matched cohorts when you need to attribute that movement to an intervention.
Make Missing Evidence a First-Class Signal
Telemetry completeness is part of the measurement. For every indicator, count observations with a start but no end, an end but no trustworthy join, required results that never reached the consumer, and records rejected because their cohort identity is unknown. Publish those counts or ratios next to latency and success distributions.
Choose the missing-data treatment before looking at the result:
- Count as an unsuccessful outcome when absence directly violates the contract, such as a required result not reaching its consumer.
- Report as incomplete and invalidate the indicator when the missing boundary prevents a defensible classification.
- Exclude only by a declared rule when the observation was never eligible, while preserving the excluded count and reason.
This prevents a telemetry outage from manufacturing a reliability improvement. It also keeps the next diagnostic honest: 6.6.4 Locating Build-Service Failures can only assign a failing layer as far as the correlated evidence permits.
Use a Small, Connected Indicator Set
A practical specification needs few indicators, each tied to a decision. For a presubmit journey, that might mean end-to-end usable-result latency and required- result completeness, supported by cache-lookup usability, queue latency, execution latency, transfer latency, and telemetry completeness for bounded action cohorts. Keep correctness as a gate rather than celebrating a fast wrong result.
Level 6 defines what these measurements mean and whether their evidence is fit for diagnosis. Organization-wide targets, error budgets, paging thresholds, and escalation rules are governance decisions. The fast feedback assumed by H.7.1 Integration Models depends on trustworthy build-service indicators, but this article does not choose that organization's acceptable latency or reliability target.
A Bazel-aware SLI names one journey or lifecycle transition, a comparable cohort, start and end events, numerator and denominator, exclusions, missing- data treatment, and an actionable owning layer. Keep end-to-end user outcomes separate from cache, transfer, queue, execution, materialization, and result- delivery indicators so a component improvement cannot masquerade as a faster or more reliable build.
Treat missing joins and missing required results as measured states, not rows to discard. Use bounded dimensions for aggregation, retain high-cardinality identities for trace drill-down, and interpret latency only alongside correctness, result completeness, and telemetry completeness.
Check your understanding · 3 questions
1.Which queue-latency design can support a reliability decision for one declared cohort?
Select one answer
2.Match each observation to the queue-latency contract treatment:
Drag each answer onto the matching prompt, or click an answer and then click a prompt
3.Which fields make a new build-service SLI inspectable and actionable?
Select all that apply
Footnotes
-
Extracting build performance metrics — distinct Bazel evidence surfaces for invocation, action, and graph measurements ↩
-
JSON Trace Profile — phase, critical-path, action, and remote setup or fetch timing evidence ↩
-
Enhanced Invocation-level Insights for Bazel Builds — invocation action timing separated into input fetch, queue wait, execution, and output upload ↩
-
Finding and Fixing Strange Builds with BuildBuddy — percentile trends, cohort drill-down, and remote queue, execution, and transfer dimensions ↩1 ↩2