@@ -59,8 +59,7 @@ export async function scaleDown(): Promise<void> {
59
59
for ( const [ runnerType , runners ] of shuffleArrayInPlace ( Array . from ( runnersDict . entries ( ) ) ) ) {
60
60
if ( runners . length < 1 || runners [ 0 ] . runnerType === undefined || runnerType === undefined ) continue ;
61
61
62
- const ghRunnersRemovableWGHRunner : Array < [ RunnerInfo , GhRunner ] > = [ ] ;
63
- const ghRunnersRemovableNoGHRunner : Array < [ RunnerInfo , GhRunner | undefined ] > = [ ] ;
62
+ let removedRunners = 0 ;
64
63
65
64
for ( const ec2runner of runners ) {
66
65
// REPO assigned runners
@@ -71,10 +70,12 @@ export async function scaleDown(): Promise<void> {
71
70
if ( ! Config . Instance . enableOrganizationRunners ) {
72
71
metrics . runnerFound ( ec2runner ) ;
73
72
if ( isRunnerRemovable ( ghRunner , ec2runner , metrics ) ) {
74
- if ( ghRunner === undefined ) {
75
- ghRunnersRemovableNoGHRunner . push ( [ ec2runner , undefined ] ) ;
76
- } else {
77
- ghRunnersRemovableWGHRunner . push ( [ ec2runner , ghRunner ] ) ;
73
+ // Process removal immediately instead of adding to array
74
+ if ( await shouldSkipRemoval ( ghRunner , ec2runner , removedRunners , runners . length , metrics ) ) {
75
+ continue ;
76
+ }
77
+ if ( await removeRunner ( ec2runner , ghRunner , metrics ) ) {
78
+ removedRunners += 1 ;
78
79
}
79
80
}
80
81
}
@@ -86,10 +87,12 @@ export async function scaleDown(): Promise<void> {
86
87
if ( Config . Instance . enableOrganizationRunners ) {
87
88
metrics . runnerFound ( ec2runner ) ;
88
89
if ( isRunnerRemovable ( ghRunner , ec2runner , metrics ) ) {
89
- if ( ghRunner === undefined ) {
90
- ghRunnersRemovableNoGHRunner . push ( [ ec2runner , undefined ] ) ;
91
- } else {
92
- ghRunnersRemovableWGHRunner . push ( [ ec2runner , ghRunner ] ) ;
90
+ // Process removal immediately instead of adding to array
91
+ if ( await shouldSkipRemoval ( ghRunner , ec2runner , removedRunners , runners . length , metrics ) ) {
92
+ continue ;
93
+ }
94
+ if ( await removeRunner ( ec2runner , ghRunner , metrics ) ) {
95
+ removedRunners += 1 ;
93
96
}
94
97
}
95
98
}
@@ -99,98 +102,6 @@ export async function scaleDown(): Promise<void> {
99
102
metrics . runnerFound ( ec2runner ) ;
100
103
}
101
104
}
102
-
103
- const ghRunnersRemovable : Array < [ RunnerInfo , GhRunner | undefined ] > =
104
- ghRunnersRemovableNoGHRunner . concat ( ghRunnersRemovableWGHRunner ) ;
105
-
106
- let removedRunners = 0 ;
107
- for ( const [ ec2runner , ghRunner ] of ghRunnersRemovable ) {
108
- // We only limit the number of removed instances here for the reason: while sorting and getting info
109
- // on getRunner[Org|Repo] we send statistics that are relevant for monitoring
110
- if (
111
- ghRunnersRemovable . length - removedRunners <= ( await minRunners ( ec2runner , metrics ) ) &&
112
- ghRunner !== undefined &&
113
- ec2runner . applicationDeployDatetime == Config . Instance . datetimeDeploy
114
- ) {
115
- continue ;
116
- }
117
-
118
- let shouldRemoveEC2 = true ;
119
- if ( ghRunner !== undefined ) {
120
- if ( Config . Instance . enableOrganizationRunners ) {
121
- console . debug (
122
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
123
- `[${ ec2runner . runnerType } ] will be removed.` ,
124
- ) ;
125
- try {
126
- await removeGithubRunnerOrg ( ghRunner . id , ec2runner . org as string , metrics ) ;
127
- metrics . runnerGhTerminateSuccessOrg ( ec2runner . org as string , ec2runner ) ;
128
- console . info (
129
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
130
- `[${ ec2runner . runnerType } ] successfuly removed.` ,
131
- ) ;
132
- } catch ( e ) {
133
- /* istanbul ignore next */
134
- console . warn (
135
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
136
- `[${ ec2runner . runnerType } ] failed to be removed. ${ e } ` ,
137
- ) ;
138
- /* istanbul ignore next */
139
- metrics . runnerGhTerminateFailureOrg ( ec2runner . org as string , ec2runner ) ;
140
- /* istanbul ignore next */
141
- shouldRemoveEC2 = false ;
142
- }
143
- } else {
144
- const repo = getRepo ( ec2runner . repo as string ) ;
145
- console . debug (
146
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
147
- `[${ ec2runner . runnerType } ] will be removed.` ,
148
- ) ;
149
- try {
150
- await removeGithubRunnerRepo ( ghRunner . id , repo , metrics ) ;
151
- metrics . runnerGhTerminateSuccessRepo ( repo , ec2runner ) ;
152
- console . info (
153
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
154
- `[${ ec2runner . runnerType } ] successfuly removed.` ,
155
- ) ;
156
- } catch ( e ) {
157
- /* istanbul ignore next */
158
- console . warn (
159
- `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
160
- `[${ ec2runner . runnerType } ] failed to be removed. ${ e } ` ,
161
- ) ;
162
- /* istanbul ignore next */
163
- metrics . runnerGhTerminateFailureRepo ( repo , ec2runner ) ;
164
- /* istanbul ignore next */
165
- shouldRemoveEC2 = false ;
166
- }
167
- }
168
- } else {
169
- if ( Config . Instance . enableOrganizationRunners ) {
170
- metrics . runnerGhTerminateNotFoundOrg ( ec2runner . org as string , ec2runner ) ;
171
- } else {
172
- metrics . runnerGhTerminateFailureRepo ( getRepo ( ec2runner . repo as string ) , ec2runner ) ;
173
- }
174
- }
175
-
176
- if ( shouldRemoveEC2 ) {
177
- removedRunners += 1 ;
178
-
179
- console . info ( `Runner '${ ec2runner . instanceId } ' [${ ec2runner . runnerType } ] will be removed.` ) ;
180
- try {
181
- await terminateRunner ( ec2runner , metrics ) ;
182
- metrics . runnerTerminateSuccess ( ec2runner ) ;
183
- } catch ( e ) {
184
- /* istanbul ignore next */
185
- metrics . runnerTerminateFailure ( ec2runner ) ;
186
- /* istanbul ignore next */
187
- console . error ( `Runner '${ ec2runner . instanceId } ' [${ ec2runner . runnerType } ] cannot be removed: ${ e } ` ) ;
188
- }
189
- } else {
190
- /* istanbul ignore next */
191
- metrics . runnerTerminateSkipped ( ec2runner ) ;
192
- }
193
- }
194
105
}
195
106
196
107
if ( Config . Instance . enableOrganizationRunners ) {
@@ -525,3 +436,101 @@ export function sortSSMParametersByUpdateTime(ssmParams: Array<SSM.ParameterMeta
525
436
return 0 ;
526
437
} ) ;
527
438
}
439
+
440
+ async function shouldSkipRemoval (
441
+ ghRunner : GhRunner | undefined ,
442
+ ec2runner : RunnerInfo ,
443
+ removedRunners : number ,
444
+ totalRunners : number ,
445
+ metrics : ScaleDownMetrics ,
446
+ ) : Promise < boolean > {
447
+ return (
448
+ totalRunners - removedRunners <= ( await minRunners ( ec2runner , metrics ) ) &&
449
+ ghRunner !== undefined &&
450
+ ec2runner . applicationDeployDatetime == Config . Instance . datetimeDeploy
451
+ ) ;
452
+ }
453
+
454
+ async function removeRunner (
455
+ ec2runner : RunnerInfo ,
456
+ ghRunner : GhRunner | undefined ,
457
+ metrics : ScaleDownMetrics ,
458
+ ) : Promise < boolean > {
459
+ let shouldRemoveEC2 = true ;
460
+
461
+ if ( ghRunner !== undefined ) {
462
+ if ( Config . Instance . enableOrganizationRunners ) {
463
+ console . debug (
464
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
465
+ `[${ ec2runner . runnerType } ] will be removed.` ,
466
+ ) ;
467
+ try {
468
+ await removeGithubRunnerOrg ( ghRunner . id , ec2runner . org as string , metrics ) ;
469
+ metrics . runnerGhTerminateSuccessOrg ( ec2runner . org as string , ec2runner ) ;
470
+ console . info (
471
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
472
+ `[${ ec2runner . runnerType } ] successfuly removed.` ,
473
+ ) ;
474
+ } catch ( e ) {
475
+ /* istanbul ignore next */
476
+ console . warn (
477
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . org } ] for EC2 '${ ec2runner . instanceId } ' ` +
478
+ `[${ ec2runner . runnerType } ] failed to be removed. ${ e } ` ,
479
+ ) ;
480
+ /* istanbul ignore next */
481
+ metrics . runnerGhTerminateFailureOrg ( ec2runner . org as string , ec2runner ) ;
482
+ /* istanbul ignore next */
483
+ shouldRemoveEC2 = false ;
484
+ }
485
+ } else {
486
+ const repo = getRepo ( ec2runner . repo as string ) ;
487
+ console . debug (
488
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
489
+ `[${ ec2runner . runnerType } ] will be removed.` ,
490
+ ) ;
491
+ try {
492
+ await removeGithubRunnerRepo ( ghRunner . id , repo , metrics ) ;
493
+ metrics . runnerGhTerminateSuccessRepo ( repo , ec2runner ) ;
494
+ console . info (
495
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
496
+ `[${ ec2runner . runnerType } ] successfuly removed.` ,
497
+ ) ;
498
+ } catch ( e ) {
499
+ /* istanbul ignore next */
500
+ console . warn (
501
+ `GH Runner instance '${ ghRunner . id } '[${ ec2runner . repo } ] for EC2 '${ ec2runner . instanceId } ' ` +
502
+ `[${ ec2runner . runnerType } ] failed to be removed. ${ e } ` ,
503
+ ) ;
504
+ /* istanbul ignore next */
505
+ metrics . runnerGhTerminateFailureRepo ( repo , ec2runner ) ;
506
+ /* istanbul ignore next */
507
+ shouldRemoveEC2 = false ;
508
+ }
509
+ }
510
+ } else {
511
+ if ( Config . Instance . enableOrganizationRunners ) {
512
+ metrics . runnerGhTerminateNotFoundOrg ( ec2runner . org as string , ec2runner ) ;
513
+ } else {
514
+ metrics . runnerGhTerminateFailureRepo ( getRepo ( ec2runner . repo as string ) , ec2runner ) ;
515
+ }
516
+ }
517
+
518
+ if ( shouldRemoveEC2 ) {
519
+ console . info ( `Runner '${ ec2runner . instanceId } ' [${ ec2runner . runnerType } ] will be removed.` ) ;
520
+ try {
521
+ await terminateRunner ( ec2runner , metrics ) ;
522
+ metrics . runnerTerminateSuccess ( ec2runner ) ;
523
+ return true ;
524
+ } catch ( e ) {
525
+ /* istanbul ignore next */
526
+ metrics . runnerTerminateFailure ( ec2runner ) ;
527
+ /* istanbul ignore next */
528
+ console . error ( `Runner '${ ec2runner . instanceId } ' [${ ec2runner . runnerType } ] cannot be removed: ${ e } ` ) ;
529
+ }
530
+ } else {
531
+ /* istanbul ignore next */
532
+ metrics . runnerTerminateSkipped ( ec2runner ) ;
533
+ }
534
+
535
+ return false ;
536
+ }
0 commit comments