{{ result.summaryTitle }}
{{ result.primary }}
{{ result.summaryLine }}
{{ badge.label }}
Queue Runners SLA {{ ciRunnerStage.peakLabel }}
CI runner capacity inputs
Names the pool in exports and guidance rows.
Use equivalent slots when one machine can run more than one job.
Use 24 for always-on runners or a smaller build-day window.
hr/day
Lower targets reserve burst, image-pull, maintenance, and autoscaler headroom.
%
Used to flag burst hours that fit average capacity but still create visible CI wait time.
min
Use recent scheduler or CI analytics volume for the same labels and runner group.
Use runner-occupied duration, not just test execution time.
min
Use recent queued/in-progress job patterns when peak hours are much busier than the daily average.
Leave 0 when runner count already represents the enforced concurrent job limit.
Leave 0 when pickup request limits are unknown or not relevant to this runner pool.
Leave 0 when jobs per day already includes retries.
%
Leave 0 when runner hours already include availability loss.
%
Capacity metricValueReadoutCopy
{{ row.metric }}{{ row.value }}{{ row.readout }}
CheckStatusActionCopy
{{ row.check }}{{ row.status }}{{ row.action }}
RunnersUtilizationHeadroomPeak clearQueue noteCopy
{{ row.runners }}{{ row.utilization }}{{ row.headroom }}{{ row.peakClear }}{{ row.note }}

        
Customize
Advanced
:

Introduction:

CI runner planning is less about counting machines and more about matching submitted work to the runner slots that can actually accept jobs. A team may have a quiet daily average and still feel blocked at 10 a.m. when pull requests, scheduled workflows, release checks, and retries all compete for the same label or runner group. Queue time appears when jobs arrive faster than available slots can drain them.

The common unit is the runner-minute. A 12 minute job consumes 12 runner-minutes, while a pool with 8 usable slots for one hour can provide 480 runner-minutes before any reserve, maintenance loss, or platform cap is considered. Runner-minutes let build, test, lint, deployment, and packaging jobs share one planning scale even when their individual durations differ.

Several terms matter before a capacity number is useful. Runner count should mean equivalent concurrent slots, not necessarily physical hosts. Utilization target is the planned share of slot time you are willing to spend on normal work before queue risk becomes uncomfortable. Queue wait target is the practical service-level agreement, or SLA, for how quickly a busy period should clear. A concurrency cap can make the effective slot count lower than the machines or autoscaled runners that appear in inventory.

CI runner capacity planning situations and risks
Situation Capacity question Risk if ignored
Daily CI volume grows Are there enough runner-minutes for ordinary work? Average utilization climbs until small bursts create visible waits.
Merge or release windows bunch jobs together Can the pool clear one busy hour quickly enough? The daily total looks acceptable while developers still wait in the peak window.
Flaky jobs retry How much extra submitted work should be included? Retries are treated as rare events even when they consume regular capacity.
Platform limits or pickup settings bind How many jobs can start at once in practice? Adding runners does not help because the cap or request limit is still lower.
CI runner capacity diagram comparing daily demand, planned headroom, and peak backlog. backlog planned service capacity average daily demand busy-hour demand ordinary hours peak hour runner-minutes per hour usable runner window

A useful estimate separates daily sustainability from burst recovery. Daily sustainability answers whether the pool has enough runner-minutes for a normal day at the selected utilization reserve. Burst recovery asks whether a one-hour spike can clear inside the queue target. Both tests matter because a runner pool can pass one and fail the other.

The estimate should be checked against observed CI analytics before changing infrastructure. Job duration percentiles, queue duration, autoscaler startup time, cache misses, image pulls, and platform-specific limits can all move the real result away from an average model. Separate pools by label, executor tier, operating system, GPU access, or protected release rules when those jobs do not compete for the same slots.

How to Use This Tool:

Model one runner pool, label, or runner group at a time. Use the same recent measurement window for job count, occupied job time, retry rate, and busy-hour pressure.

  1. Enter Runner pool with the label or group name you want carried into the result tables and copied output.
  2. Set Runner count to equivalent concurrent slots. If one host can run two jobs at once, count it as two slots.
  3. Set Usable runner hours to the daily window when the pool can accept jobs. Use 24 for always-on capacity or a smaller number when runners shut down overnight or are reserved for maintenance.
  4. Choose Target utilization and Queue wait target. Lower utilization keeps more headroom; the queue target defines the allowed clear time for the modeled one-hour burst.
  5. Enter Jobs per day, Average job time, and Busy-hour multiplier. Use runner-occupied time for average job time, including checkout, setup, cache restore, test execution, artifact upload, and teardown when those steps hold the slot.
  6. Open Advanced when platform limits apply. Use Configured concurrency cap for a hard active-job limit, Request concurrency for job-pickup request limits, Retry rate for extra submitted work, and Unavailable capacity for lost runner time not already removed from usable hours.
  7. Fix Check runner inputs messages before trusting the numbers. For example, average job time must be positive when jobs per day is above zero, target utilization must be 1% to 100%, and unavailable capacity cannot exceed 95%.
  8. Review Runner Capacity first, then compare Queue Pressure Audit, Runner Scenario Table, Runner Capacity Curve, Peak Wait SLA Curve, and JSON. A result is ready when daily utilization, peak clear time, cap status, and request-concurrency warnings all agree with the decision you plan to make.

Interpreting Results:

Daily runner demand is the adjusted job count multiplied by occupied minutes per job. Planned capacity is the sustainable runner-minute supply after effective slots, usable hours, unavailable time, and the utilization target are applied. If Target utilization used is above 100%, the pool is short on an average day.

Peak clear time is the burst warning. It estimates how long the excess work from a one-hour busy period takes to drain. A daily pass with a failed peak wait target means the pool has enough total work time but not enough burst service rate.

CI runner capacity result signals
Signal Meaning Check before acting
Effective runner slots below runner count A positive concurrency cap is limiting useful capacity. Raise the platform cap or model the capped pool separately before adding more nominal runners.
Average margin is negative Daily runner-minute demand exceeds planned capacity. Confirm recent job duration data and retry volume before changing slot counts.
Peak wait target is over target A one-hour burst clears too slowly for the selected queue target. Compare the smallest passing runner count with the Peak Wait SLA Curve.
Pickup requests reports a bottleneck Request concurrency is lower than effective slots. Review runner long-polling, pickup latency, and request limits in the CI platform.
Busy-hour slots exceeds effective slots Peak throughput is tighter than average-day throughput. Check whether busy hours come from predictable schedules, merge queues, or flaky retries that can be smoothed.

Do not remove slots simply because the average day passes. Use queue duration logs, job duration percentiles, runner startup time, retry causes, and platform concurrency settings to confirm that the modeled bottleneck matches the real queue.

Technical Details:

Runner capacity has two linked mechanics: service volume and burst drain rate. Service volume is the number of runner-minutes the pool can provide during the usable day after capacity loss and utilization reserve. Burst drain rate is the spare slot service rate available after average demand is already consuming part of the pool.

Effective slots are capped when a positive concurrency limit is lower than the nominal runner count. That cap affects daily capacity, peak slot requirements, and scenario rows. A separate request-concurrency value does not reduce the arithmetic slot count, but it flags a pickup bottleneck when fewer job requests can be in flight than there are active slots.

Formula Core:

The model adjusts job count for retries, converts demand to runner-minutes, and compares that demand with planned capacity and busy-hour service rate.

Jadj = Jday×(1+r) D = Jadj×T S = runner count, limited by any positive lower concurrency cap P = S×H×60×(1-a)×U average-day slots = DH×60×(1-a)×U B = DH×M W = max(0,B-S×60×(1-a)×U)max(0.1,S×(1-a)-DH×60)

Here Jday is jobs per day, r is retry rate as a decimal, T is average occupied job minutes, D is daily runner-minute demand, S is effective runner slots, H is usable runner hours per day, a is unavailable capacity, U is target utilization, M is the busy-hour multiplier, B is busy-hour runner-minute demand, P is planned capacity, and W is peak clear time in minutes.

Slot requirements are rounded up because fractional slots cannot run concurrent jobs. The peak wait search tests runner counts and chooses the smallest count where planned utilization is at or below 100% and peak clear time is at or below the queue wait target. If a positive concurrency cap stays below the needed count, raising the nominal runner count will not produce a passing scenario.

CI runner validation and boundary rules
Quantity Boundary Planning effect
Runner count Must be greater than 0 and is rounded to whole slots. Use equivalent concurrency slots, not asset inventory, when they differ.
Usable runner hours Must be greater than 0 and no more than 24 hours per day. Shutdown windows and maintenance reduce service volume.
Target utilization Must be 1% to 100%. Lower values reserve more headroom and increase required slots.
Busy-hour multiplier Must be at least 1. Values above 1 model demand concentrated above the average hour.
Unavailable capacity Must be 0% to 95%. Lost time is removed before utilization and queue math.
Request concurrency When positive and lower than effective slots, it is flagged. Pickup limits can delay starts even when enough slots exist.

With the default inputs, 900 jobs at 9 minutes create 8,100 runner-minutes per day. Twelve slots running 20 usable hours at a 70% utilization target provide 10,080 planned runner-minutes, so average-day slots round up to 10. A 1.35 busy-hour multiplier raises the one-hour peak to about 547 runner-minutes, which requires 14 slots for peak throughput and clears in about 8.1 minutes against a 10 minute target.

Worked Examples:

Shared Linux pool with spare average capacity

Use 12 runners, 20 usable hours, 900 jobs per day, 9 occupied minutes, and a 70% utilization target. The daily demand is 8,100 runner-minutes, planned capacity is 10,080 runner-minutes, and Average-day slots is 10. The average day fits, but the 1.35 busy-hour multiplier still pushes Busy-hour slots to 14.

Release window that misses the peak target

A release pool with 10 slots, 16 usable hours, 900 jobs at 6 minutes, a 10% retry rate, 5% unavailable capacity, and a 2.20 busy-hour multiplier creates 5,940 runner-minutes per day. The average day fits a 70% target, but Peak clear time is about 2.1 hours, so a 10 minute queue target fails.

Concurrency cap blocks a larger runner count

Set Runner count to 16 and Configured concurrency cap to 12 when the CI platform allows only 12 active jobs for the group. Effective runner slots stays at 12, scenario rows past the cap show that the cap binds, and added machines will not improve the calculated capacity until the cap changes.

Runtime input prevents a result

If Jobs per day is 250 and Average job time is 0, the summary switches to Check values. Replace the zero with runner-occupied duration from recent jobs before using any capacity or queue result.

FAQ:

Should setup, checkout, and artifact upload count in average job time?

Yes. Count the time the job occupies a runner slot, not only the test command. Checkout, image pulls, dependency setup, cache restore, execution, artifact upload, and teardown all consume capacity when the slot is unavailable to other jobs.

Why can the average day fit while the queue target fails?

Average capacity spreads demand across usable hours. The queue target checks a one-hour burst. A pool can have enough runner-minutes for the day and still clear a concentrated burst too slowly.

What should I enter for runner count?

Enter equivalent concurrent slots for the pool. A single host that runs one job is one slot, while a host configured to run two independent jobs counts as two slots if both jobs can actually run at the same time.

What does request concurrency change?

Request concurrency is a pickup limit, not extra compute capacity. When it is positive and below effective slots, the tool flags a possible assignment delay even though the runner-minute calculation still uses the effective slot count.

Does the calculation upload CI job data?

No server-side processing is needed for the estimate. The calculation uses the values in the browser. Copied tables, downloaded files, and shared values can still expose pool names, job volumes, and capacity assumptions outside the page.

Glossary:

Runner slot
One unit of CI concurrency that can execute one job at a time.
Runner-minute
One minute of occupied runner slot time.
Target utilization
The planned sustainable share of usable runner time after reserving headroom.
Busy-hour multiplier
A factor that turns average hourly demand into a short peak demand estimate.
Concurrency cap
A platform or runner group limit that can reduce effective slots below nominal runner count.
Peak clear time
The estimated time needed to drain one-hour burst work that exceeds planned service capacity.