@@ -3,6 +3,7 @@ package e2eautoscaler
3
3
import (
4
4
"fmt"
5
5
"testing"
6
+ "time"
6
7
7
8
"github.com/onsi/gomega"
8
9
corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
@@ -355,3 +356,69 @@ func TestRayClusterAutoscalerMinReplicasUpdate(t *testing.T) {
355
356
})
356
357
}
357
358
}
359
+
360
+ func TestRayClusterAutoscalerV2IdleTimeout (t * testing.T ) {
361
+ // Only test with the V2 Autoscaler
362
+ name := "Create a RayCluster with autoscaler v2 enabled"
363
+ tc := tests ["Create a RayCluster with autoscaler v2 enabled" ]
364
+
365
+ test := With (t )
366
+ g := gomega .NewWithT (t )
367
+
368
+ // Create a namespace
369
+ namespace := test .NewTestNamespace ()
370
+
371
+ // Minimum Ray Version for custom idleTimeoutSeconds
372
+ idleTimeoutMinRayVersion := "2.40.0"
373
+
374
+ customIdleTimeoutSeconds := int32 (30 )
375
+ defaultIdleTimeoutSeconds := int32 (60 )
376
+
377
+ test .T ().Run (name , func (_ * testing.T ) {
378
+ rayClusterSpecAC := rayv1ac .RayClusterSpec ().
379
+ WithEnableInTreeAutoscaling (true ).
380
+ WithRayVersion (idleTimeoutMinRayVersion ).
381
+ WithHeadGroupSpec (rayv1ac .HeadGroupSpec ().
382
+ WithRayStartParams (map [string ]string {"num-cpus" : "0" }).
383
+ WithTemplate (tc .HeadPodTemplateGetter ())).
384
+ WithWorkerGroupSpecs (
385
+ rayv1ac .WorkerGroupSpec ().
386
+ WithReplicas (1 ).
387
+ WithMinReplicas (0 ).
388
+ WithMaxReplicas (4 ).
389
+ WithGroupName ("no-idle-timeout-group" ).
390
+ WithRayStartParams (map [string ]string {"num-cpus" : "1" }).
391
+ WithTemplate (tc .WorkerPodTemplateGetter ()),
392
+ rayv1ac .WorkerGroupSpec ().
393
+ WithReplicas (1 ).
394
+ WithMinReplicas (0 ).
395
+ WithMaxReplicas (4 ).
396
+ WithIdleTimeoutSeconds (customIdleTimeoutSeconds ).
397
+ WithGroupName ("custom-idle-timeout-group" ).
398
+ WithRayStartParams (map [string ]string {"num-cpus" : "1" }).
399
+ WithTemplate (tc .WorkerPodTemplateGetter ()),
400
+ )
401
+ rayClusterAC := rayv1ac .RayCluster ("ray-cluster" , namespace .Name ).WithSpec ((rayClusterSpecAC ))
402
+
403
+ rayCluster , err := test .Client ().Ray ().RayV1 ().RayClusters (namespace .Name ).Apply (test .Ctx (), rayClusterAC , TestApplyOptions )
404
+ g .Expect (err ).NotTo (gomega .HaveOccurred ())
405
+ test .T ().Logf ("Created RayCluster %s/%s successfully" , rayCluster .Namespace , rayCluster .Name )
406
+
407
+ // Wait for RayCluster to become ready and verify the number of available worker replicas.
408
+ g .Eventually (RayCluster (test , rayCluster .Namespace , rayCluster .Name ), TestTimeoutMedium ).
409
+ Should (gomega .WithTransform (RayClusterState , gomega .Equal (rayv1 .Ready )))
410
+ g .Expect (GetRayCluster (test , rayCluster .Namespace , rayCluster .Name )).To (gomega .WithTransform (RayClusterDesiredWorkerReplicas , gomega .Equal (int32 (2 ))))
411
+
412
+ headPod , err := GetHeadPod (test , rayCluster )
413
+ g .Expect (err ).NotTo (gomega .HaveOccurred ())
414
+ test .T ().Logf ("Found head pod %s/%s" , headPod .Namespace , headPod .Name )
415
+
416
+ // After customIdleTimeoutSeconds, the replica in the worker group with custom idleTimeoutSeconds set should be scaled down.
417
+ g .Eventually (RayCluster (test , rayCluster .Namespace , rayCluster .Name ), time .Duration (customIdleTimeoutSeconds )* time .Second ).
418
+ Should (gomega .WithTransform (RayClusterDesiredWorkerReplicas , gomega .Equal (int32 (1 ))))
419
+
420
+ // After the default idleTimeoutSeconds, all worker replicas should be scaled down.
421
+ g .Eventually (RayCluster (test , rayCluster .Namespace , rayCluster .Name ), time .Duration (defaultIdleTimeoutSeconds )* time .Second ).
422
+ Should (gomega .WithTransform (RayClusterDesiredWorkerReplicas , gomega .Equal (int32 (0 ))))
423
+ })
424
+ }
0 commit comments