CI Runner Capacity Calculator
Estimate CI runner slots from workload minutes and peak demand, then check utilization headroom and queue-clear time against platform caps and retry load.| Planning item | Result | Use | Copy |
|---|---|---|---|
| {{ row.item }} | {{ row.result }} | {{ row.use }} |
| Check | Status | Operator action | Copy |
|---|---|---|---|
| {{ row.check }} | {{ row.status }} | {{ row.action }} |
A continuous integration (CI) runner pool can look adequate over a whole day and still build a queue during the busiest merge or release hour. Daily workload measures sustained demand. Peak concentration, platform caps, pickup behavior, failures, and autoscaler delay determine whether jobs start when the team expects them to.
The useful planning unit is an occupied runner-minute. A nine-minute job consumes nine minutes of one concurrent slot, including checkout, setup, cache restore, execution, artifact upload, and teardown whenever the slot stays occupied. Multiplying occupied duration by submitted jobs makes different runner pools easier to compare than counting jobs alone.
| Quantity | Planning use | Misread to avoid |
|---|---|---|
| Runner slot | One job that can execute concurrently | Counting hosts when each host supports several jobs. |
| Target utilization | Share of available runner time reserved for normal demand | Planning at 100% and leaving no room for variation. |
| Busy-hour multiplier | Concentration of runner-minutes in the peak hour | Using a daily average as if arrivals were uniform. |
| Concurrency cap | Maximum active jobs allowed by a platform, group, or scale set | Adding nominal slots without raising the binding cap. |
| Pickup concurrency | Requests that can wait for new jobs at once | Treating pickup requests as execution capacity. |
Headroom is a policy choice rather than wasted capacity. Image pulls, noisy neighbors, maintenance, larger-than-average jobs, retries, and sudden commit bursts all consume room that a perfect average does not show. A lower target utilization asks for more slots but makes the plan less sensitive to those variations.
Queue time is especially difficult to predict from summary data. This capacity model represents one busy hour as excess runner-minutes and estimates how long the pool takes to drain that excess after accounting for ongoing average demand. It does not reconstruct individual arrival times, workflow dependencies, job priorities, matrix fan-out, or autoscaler startup.
Use a consistent measurement window for job count and occupied duration, and split pools that serve materially different executors or hardware. A blended average across Linux, macOS, GPU, privileged, or region-specific jobs can recommend slots that no actual queue can use.
How to Use This Tool:
Define one runner pool, measure its completed workload over a representative period, and add the limits that can prevent nominal slots from accepting jobs.
- Name the Runner pool and enter equivalent Current runner slots. Count concurrent job positions rather than physical machines.
- Set Usable hours per day and Target utilization. Use 24 hours for an always-on pool, then record maintenance or autoscaler loss under unavailable capacity only once.
- Enter Jobs per day and representative Occupied minutes per job from the same pool and period. If the job count already includes reruns, leave additional retry rate at zero.
- Set the Busy-hour multiplier from observed queued and running work during peak periods, then choose the maximum acceptable Peak wait SLA for draining the modeled excess.
- Add a configured concurrency cap, pickup request concurrency, retry load, and unavailable capacity when they apply. Read Capacity plan for recommended slots and Operating checks for any cap, queue, or pickup warning.
Interpreting Results:
Average-day minimum is the smallest whole slot count that fits daily runner-minute demand inside the selected utilization target. Recommended slots can be higher because they must also drain the modeled peak excess within the queue-clear target.
- Effective slots is the lesser of nominal slots and a positive configured cap. A binding cap can make added runners invisible to active-job capacity.
- Planned utilization above 100% means daily demand exceeds capacity after target utilization and unavailability are applied.
- Peak clear time estimates how long excess work from one modeled busy hour takes to drain. It is not a prediction for an individual job.
- A pickup warning means the entered request concurrency is below effective execution slots. Check platform behavior and long-polling metrics before changing it.
- Compare repeat runs only when pool boundaries, measurement window, job-duration definition, retry treatment, and usable hours stay consistent.
Technical Details:
Daily demand is adjusted for retry work and converted to runner-minutes. Each slot contributes usable minutes after the unavailable-capacity allowance, and only the target-utilization share is planned for normal work.
Formula Core:
The average-day calculation uses the following quantities.
| Symbol | Meaning | Unit |
|---|---|---|
| J | Submitted jobs per day before additional retry load | jobs/day |
| r | Additional retry rate as a decimal | Ratio |
| M | Average occupied minutes per job | minutes/job |
| H | Usable operating hours per day | hours/day |
| u | Unavailable-capacity share | Ratio |
| t | Target utilization share | Ratio |
| D | Adjusted daily runner-minute demand | runner-minutes/day |
A positive concurrency cap replaces nominal slots with the smaller capped value for current-capacity checks. Actual utilization divides demand by all available runner-minutes; planned utilization divides it by the target-utilization share.
Peak Queue Mechanism:
The busy-hour multiplier applies to average runner-minute demand per hour. Excess is the portion above planned hourly capacity. Drain rate is the available concurrent work rate after subtracting ongoing average demand, with a small positive floor to keep the estimate finite.
b is the busy-hour multiplier, P is peak runner-minutes per hour, X is excess runner-minutes, and q is runner-minutes cleared per wall-clock minute. Recommended slots are found by testing whole counts from the average-day minimum upward until planned utilization is at most 100% and peak clear time is at most the entered target. The search does not assume a configured cap can be raised; a lower cap is reported separately as blocking the plan.
| Status | Rule |
|---|---|
| Cap blocked | A positive configured cap is below recommended slots. |
| Average shortfall | Planned utilization is greater than 100%. |
| Queue target miss | Peak clear time is greater than the selected target. |
| Pickup review | A positive pickup request concurrency is below effective slots. |
| Healthy | None of the earlier rules applies. |
Whole-slot requirements round upward. Other calculations retain full numeric precision before display formatting. Inputs allow up to 100,000 slots; a workload requiring more is rejected rather than silently capped as a valid plan.
Limitations:
The queue-clear result is a deterministic planning approximation, not a discrete-event simulation or a service-level guarantee.
- One average duration does not capture long-tail jobs, workflow dependencies, priorities, cancellation, or matrix fan-out.
- The busy-hour multiplier models one concentrated hour. It does not reproduce the timing of individual arrivals or several consecutive peaks.
- Unavailable capacity is a single percentage and cannot separately model autoscaler startup, image pulls, executor failures, or maintenance windows.
- Platform concurrency limits and runner settings change. Check the current account, group, runner, and hosting limits rather than copying a generic value.
- Pickup concurrency is a diagnostic input. Its meaning depends on the CI platform and runner configuration, and increasing it does not create execution slots.
Worked Examples:
Shared Linux pool at the default workload
Nine hundred jobs at 9 occupied minutes create 8,100 runner-minutes per day. With 20 usable hours, 70% target utilization, and no retry or availability loss, each slot contributes 840 planned minutes. The average-day minimum rounds up to 10 slots, but a 1.35 busy-hour multiplier needs 12 slots to clear the modeled excess in about 8.14 minutes, inside a 10-minute target.
Release burst needs more peak capacity
Keeping the same daily workload but increasing the busy-hour multiplier to 1.6 does not change the 10-slot average minimum. Twelve slots would take about 27.43 minutes to drain the modeled excess, so the recommendation rises to 14 slots for the 10-minute target. A configured cap below 14 would still block that plan even if 14 nominal slots were provisioned.
References:
- Actions Limits, GitHub Docs.
- Advanced Configuration, GitLab Docs.