Skip to content
Latchkey

How to Measure CI Queue Time and Its Hidden Cost

Queue time is invisible on the minutes bill but expensive in engineer wait and, for self-hosted fleets, in mis-sized capacity.

Compute the gap between when a run is created and when its job starts, using the run and jobs API timestamps, then track it to right-size capacity.

Steps

  • Read created_at for the run and started_at for each job from the API.
  • The difference is queue time; track its distribution, not just the average.
  • Rising queue time on self-hosted means scale up; on hosted it signals concurrency limits.

Compute queue time for a run

Terminal
# started_at minus created_at, per job, in seconds
curl -sS -H "Authorization: Bearer $GH_TOKEN" \
  "https://api.github.com/repos/my-org/api/actions/runs/$RUN_ID/jobs" \
  | jq -r '.jobs[] | "\(.name) \((.started_at|fromdate) - (.created_at|fromdate))s"'

Gotchas

  • On hosted runners, long queues usually mean you hit a concurrency limit, not a runner shortage.
  • On self-hosted, idle runners waiting for work cost money while queues elsewhere grow; balance the pool.
  • Queue time does not appear in billed minutes, so it hides until you measure it deliberately.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →