Description
When minRunners > 0 is configured on an AutoScalingRunnerSet and a config change is applied (via Helm upgrade, ArgoCD sync, etc.), the controller enters a deadlock state where the new AutoscalingListener cannot be created.
Steps to Reproduce
- Configure a runner scale set with
minRunners: 1 (or higher)
- Wait for idle runners to be created
- Apply any config change that triggers listener recreation (e.g., change
minRunners from 1 to 3, modify env vars, change volumes, etc.)
- Observe the controller logs
Expected Behavior
The controller should gracefully drain idle runners and recreate the listener with the new configuration, or apply the config change without requiring a full drain.
Actual Behavior
The controller logs show:
"Creating a new AutoscalingListener is waiting for the running and pending runners to finish. Waiting for the running and pending runners to finish:", "running":1, "pending":0
The controller:
- Deletes the old
AutoscalingListener
- Waits for all runners to reach 0 before creating the new listener
- But
minRunners > 0 keeps idle runners alive indefinitely
- Deadlock: new listener never gets created, runners remain idle forever
Workaround
Manually delete the EphemeralRunnerSet:
kubectl delete ephemeralrunnersets -n <namespace> --all
This unblocks the controller, which then creates a new ERS and listener with the correct configuration.
Environment
- ARC version: 0.14.2 (latest as of 2026-07-11)
- Controller image:
ghcr.io/actions/gha-runner-scale-set-controller:0.14.2
- Kubernetes: 1.30+
- Deployment method: Helm via ArgoCD
Additional Context
This is a fundamental design issue: the controller requires all runners to be drained before applying config changes, but minRunners prevents the drain from completing. The only safe pattern currently is to always keep minRunners: 0, which defeats the purpose of having warm runners for faster job startup.
A potential fix could be:
- Allow the controller to force-terminate idle runners during config transitions
- Or apply config changes in-place without requiring a full listener recreation
- Or add a timeout after which idle runners are terminated to unblock the transition
Description
When
minRunners > 0is configured on anAutoScalingRunnerSetand a config change is applied (via Helm upgrade, ArgoCD sync, etc.), the controller enters a deadlock state where the newAutoscalingListenercannot be created.Steps to Reproduce
minRunners: 1(or higher)minRunnersfrom 1 to 3, modify env vars, change volumes, etc.)Expected Behavior
The controller should gracefully drain idle runners and recreate the listener with the new configuration, or apply the config change without requiring a full drain.
Actual Behavior
The controller logs show:
The controller:
AutoscalingListenerminRunners > 0keeps idle runners alive indefinitelyWorkaround
Manually delete the
EphemeralRunnerSet:This unblocks the controller, which then creates a new ERS and listener with the correct configuration.
Environment
ghcr.io/actions/gha-runner-scale-set-controller:0.14.2Additional Context
This is a fundamental design issue: the controller requires all runners to be drained before applying config changes, but
minRunnersprevents the drain from completing. The only safe pattern currently is to always keepminRunners: 0, which defeats the purpose of having warm runners for faster job startup.A potential fix could be: