-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Repository-wide RunnerDeployment Autoscaling (#57)
* feat: Repository-wide RunnerDeployment Autoscaling This adds `maxReplicas` and `minReplicas` to the RunnerDeploymentSpec. If and only if both fields are set, the controller computes and sets desired `replicas` automatically depending on the demand. The number of demanded runner replicas is computed by `queued workflow runs + in_progress workflow runs` for the repository. The support for organizational runners is not included. Ref #10
- Loading branch information
KUOKA Yusuke
authored
Jun 27, 2020
1 parent
512cae6
commit 5bb2694
Showing
12 changed files
with
520 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package controllers | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/summerwind/actions-runner-controller/api/v1alpha1" | ||
"strings" | ||
) | ||
|
||
type NotSupported struct { | ||
} | ||
|
||
var _ error = NotSupported{} | ||
|
||
func (e NotSupported) Error() string { | ||
return "Autoscaling is currently supported only when spec.repository is set" | ||
} | ||
|
||
func (r *RunnerDeploymentReconciler) determineDesiredReplicas(rd v1alpha1.RunnerDeployment) (*int, error) { | ||
if rd.Spec.Replicas != nil { | ||
return nil, fmt.Errorf("bug: determineDesiredReplicas should not be called for deplomeny with specific replicas") | ||
} else if rd.Spec.MinReplicas == nil { | ||
return nil, fmt.Errorf("runnerdeployment %s/%s is missing minReplicas", rd.Namespace, rd.Name) | ||
} else if rd.Spec.MaxReplicas == nil { | ||
return nil, fmt.Errorf("runnerdeployment %s/%s is missing maxReplicas", rd.Namespace, rd.Name) | ||
} | ||
|
||
var replicas int | ||
|
||
repoID := rd.Spec.Template.Spec.Repository | ||
if repoID == "" { | ||
return nil, NotSupported{} | ||
} | ||
|
||
repo := strings.Split(repoID, "/") | ||
user, repoName := repo[0], repo[1] | ||
list, _, err := r.GitHubClient.Actions.ListRepositoryWorkflowRuns(context.TODO(), user, repoName, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var total, inProgress, queued, completed, unknown int | ||
|
||
for _, r := range list.WorkflowRuns { | ||
total++ | ||
|
||
// In May 2020, there are only 3 statuses. | ||
// Follow the below links for more details: | ||
// - https://developer.github.com/v3/actions/workflow-runs/#list-repository-workflow-runs | ||
// - https://developer.github.com/v3/checks/runs/#create-a-check-run | ||
switch r.GetStatus() { | ||
case "completed": | ||
completed++ | ||
case "in_progress": | ||
inProgress++ | ||
case "queued": | ||
queued++ | ||
default: | ||
unknown++ | ||
} | ||
} | ||
|
||
minReplicas := *rd.Spec.MinReplicas | ||
maxReplicas := *rd.Spec.MaxReplicas | ||
necessaryReplicas := queued + inProgress | ||
|
||
var desiredReplicas int | ||
|
||
if necessaryReplicas < minReplicas { | ||
desiredReplicas = minReplicas | ||
} else if necessaryReplicas > maxReplicas { | ||
desiredReplicas = maxReplicas | ||
} else { | ||
desiredReplicas = necessaryReplicas | ||
} | ||
|
||
rd.Status.Replicas = &desiredReplicas | ||
replicas = desiredReplicas | ||
|
||
r.Log.V(1).Info( | ||
"Calculated desired replicas", | ||
"computed_replicas_desired", desiredReplicas, | ||
"spec_replicas_min", minReplicas, | ||
"spec_replicas_max", maxReplicas, | ||
"workflow_runs_completed", completed, | ||
"workflow_runs_in_progress", inProgress, | ||
"workflow_runs_queued", queued, | ||
"workflow_runs_unknown", unknown, | ||
) | ||
|
||
return &replicas, nil | ||
} |
Oops, something went wrong.