@@ -65,7 +65,7 @@ func computeDesiredFleetSize(pol autoscalingv1.FleetAutoscalerPolicy, f *agonesv
65
65
case autoscalingv1 .SchedulePolicyType :
66
66
return applySchedulePolicy (pol .Schedule , f , gameServerLister , nodeCounts , time .Now ())
67
67
case autoscalingv1 .ChainPolicyType :
68
- return applyChainPolicy (pol .Chain , f , gameServerLister , nodeCounts )
68
+ return applyChainPolicy (pol .Chain , f , gameServerLister , nodeCounts , time . Now () )
69
69
}
70
70
71
71
return 0 , false , errors .New ("wrong policy type, should be one of: Buffer, Webhook, Counter, List" )
@@ -373,95 +373,96 @@ func applySchedulePolicy(s *autoscalingv1.SchedulePolicy, f *agonesv1.Fleet, gam
373
373
return 0 , false , errors .Errorf ("cannot apply SchedulePolicy unless feature flag %s is enabled" , runtime .FeatureScheduledAutoscaler )
374
374
}
375
375
376
- fmt .Println ("Above" )
377
376
if isScheduleActive (s , currentTime ) {
378
- fmt .Println ("Inside" )
379
377
return computeDesiredFleetSize (s .Policy , f , gameServerLister , nodeCounts )
380
378
}
381
379
382
- var replicas int32
383
- fmt .Println ("Outside" )
384
- if f != nil {
385
- replicas = f .Status .Replicas
386
- }
387
-
388
- return replicas , false , nil
380
+ // If the schedule wasn't active then return the current replica amount of the fleet
381
+ return f .Status .Replicas , false , errors .Errorf ("inactive schedule, policy not applicable at this time: %s" , currentTime )
389
382
}
390
383
391
- func applyChainPolicy (c autoscalingv1.ChainPolicy , f * agonesv1.Fleet , gameServerLister listeragonesv1.GameServerLister , nodeCounts map [string ]gameservers.NodeCount ) (int32 , bool , error ) {
384
+ func applyChainPolicy (c autoscalingv1.ChainPolicy , f * agonesv1.Fleet , gameServerLister listeragonesv1.GameServerLister , nodeCounts map [string ]gameservers.NodeCount , currentTime time. Time ) (int32 , bool , error ) {
392
385
// Ensure the scheduled autoscaler feature gate is enabled
393
386
if ! runtime .FeatureEnabled (runtime .FeatureScheduledAutoscaler ) {
394
387
return 0 , false , errors .Errorf ("cannot apply ChainPolicy unless feature flag %s is enabled" , runtime .FeatureScheduledAutoscaler )
395
388
}
396
389
390
+ replicas := f .Status .Replicas
391
+ var limited bool
392
+ var err error
393
+
397
394
// Loop over all entries in the chain
398
395
for _ , entry := range c {
399
396
switch entry .Type {
400
397
case autoscalingv1 .SchedulePolicyType :
401
- schedRep , schedLim , schedErr : = applySchedulePolicy (entry .Schedule , f , gameServerLister , nodeCounts , time . Now () )
402
- // If the schedule is active and no error was returned from the policy , then return the replicas, limited and error
403
- if isScheduleActive ( entry . Schedule , time . Now ()) && schedErr == nil {
404
- return schedRep , schedLim , nil
398
+ replicas , limited , err = applySchedulePolicy (entry .Schedule , f , gameServerLister , nodeCounts , currentTime )
399
+ // If no error was returned from the schedule policy (schedule is active and/or webhook policy within schedule was successful) , then return the values given
400
+ if err == nil {
401
+ return replicas , limited , nil
405
402
}
406
403
case autoscalingv1 .WebhookPolicyType :
407
- webhookRep , webhookLim , webhookErr := applyWebhookPolicy (entry .Webhook , f )
408
- if webhookErr == nil {
409
- return webhookRep , webhookLim , nil
404
+ replicas , limited , err = applyWebhookPolicy (entry .Webhook , f )
405
+ // If no error was returned from the webhook policy, then return the values given
406
+ if err == nil {
407
+ return replicas , limited , nil
410
408
}
411
409
default :
410
+ // Every other policy type we just want to compute the desired fleet and return it
412
411
return computeDesiredFleetSize (entry .FleetAutoscalerPolicy , f , gameServerLister , nodeCounts )
413
412
}
414
413
}
415
414
416
- return f .Status .Replicas , false , nil
415
+ // Fall off the chain
416
+ return replicas , limited , err
417
417
}
418
418
419
419
// isScheduleActive checks if a chain entry's is active and returns a boolean, true if active, false otherwise
420
420
func isScheduleActive (s * autoscalingv1.SchedulePolicy , currentTime time.Time ) bool {
421
- // var now = time.Now()
422
- // fmt.Printf("Time Now Is: %s\n", now)
423
- cronDelta := time .Minute * - 2
421
+ // When retrieving the next available cronTime it returns the next minute e.g. if you want a policy to run every minute (all the time)
422
+ // If the current time is 1:00, the next start time returned will be 1:01, thus we use a cronDelta of 90 seconds to
423
+ // adjust to the minute delta (since the next start time will always be ahead of the current time by 1 minute when the schedule is active).
424
+ cronDelta := (time .Minute * - 1 ) + (time .Second * - 30 )
424
425
425
- // If a start time is present and the current time is before the start time, the schedule is inactive so return false
426
+ // If the current time is before the start time, the schedule is inactive so return false
426
427
startTime := s .Between .Start .Time
427
- if ! startTime .IsZero () && currentTime .Before (startTime ) {
428
- fmt .Println ("ONE" )
428
+ if currentTime .Before (startTime ) {
429
429
return false
430
430
}
431
431
432
432
// If an end time is present and the current time is after the end time, the schedule is inactive so return false
433
433
endTime := s .Between .End .Time
434
434
if ! endTime .IsZero () && currentTime .After (endTime ) {
435
- fmt .Println ("TWO" )
436
435
return false
437
436
}
438
437
439
438
// If no startCron field is specified, then it's automatically true (duration is no longer relevant since we're always running)
440
439
if s .ActivePeriod .StartCron == "" {
441
- fmt .Println ("THREE" )
442
440
return true
443
441
}
444
442
445
443
location , _ := time .LoadLocation (s .ActivePeriod .Timezone )
446
444
startCron , _ := cron .ParseStandard (s .ActivePeriod .StartCron )
447
- nextStartTime := startCron . Next ( currentTime . In ( location )). Add ( cronDelta )
448
- duration , err := time . ParseDuration ( s . ActivePeriod . Duration )
445
+ duration , _ := time . ParseDuration ( s . ActivePeriod . Duration )
446
+ nextStartTime := startCron . Next ( currentTime . In ( location ) )
449
447
450
448
// If there's an err, then the duration field is empty, meaning duration is indefinite
451
- if err != nil {
449
+ if s . ActivePeriod . Duration == "" {
452
450
duration = 0 // Indefinite duration if not set
453
451
}
454
452
455
453
// If the current time is after the next start time, and the duration is indefinite or the current time is before the next start time + duration,
456
- // then return true
457
- fmt .Printf ("Current Time: %s\n " , currentTime )
458
- fmt .Printf ("Next Start Time: %s\n " , nextStartTime )
459
- if currentTime .After (nextStartTime ) && (duration == 0 || currentTime .Before (nextStartTime .Add (duration ))) {
460
- fmt .Println ("FOUR" )
454
+ // then return true.
455
+ // e.g.
456
+ // startCron = * * * * *
457
+ // currentTime = 2024-08-01T14:30:00Z // 2:30 PM UTC on August 1, 2024
458
+ // nextStartTime = 2024-08-01T14:31:00Z // 2:31 PM UTC on August 1, 2024
459
+ // duration = 1 hour
460
+ // cronDelta = 1 Minute Delta 30 seconds
461
+ // This would return true since the currentTime > nextStartTime - cronDelta AND the currentTime < nextStartTime + duration.
462
+ if currentTime .After (nextStartTime .Add (cronDelta )) && (duration == 0 || currentTime .Before (nextStartTime .Add (duration ))) {
461
463
return true
462
464
}
463
465
464
- fmt .Println ("FIVE" )
465
466
return false
466
467
}
467
468
0 commit comments