99import asyncio
1010import datetime
1111import logging
12+ import random
1213from collections .abc import AsyncIterator , Awaitable , Callable , Iterator , Sequence
1314from copy import deepcopy
1415from dataclasses import dataclass
@@ -1236,6 +1237,7 @@ async def test_cluster_adapts_machines_on_the_fly(
12361237 osparc_docker_label_keys : StandardSimcoreDockerLabels ,
12371238 ec2_instance_custom_tags : dict [str , str ],
12381239 instance_type_filters : Sequence [FilterTypeDef ],
1240+ async_docker_client : aiodocker .Docker ,
12391241 scale_up_params1 : _ScaleUpParams ,
12401242 scale_up_params2 : _ScaleUpParams ,
12411243):
@@ -1252,7 +1254,7 @@ async def test_cluster_adapts_machines_on_the_fly(
12521254
12531255 #
12541256 # 1. create the first batch of services requiring the initial machines
1255- await asyncio .gather (
1257+ first_batch_services = await asyncio .gather (
12561258 * (
12571259 create_service (
12581260 task_template
@@ -1313,8 +1315,8 @@ async def test_cluster_adapts_machines_on_the_fly(
13131315 for _ in range (scale_up_params2 .num_services )
13141316 )
13151317 )
1318+ # scaling will do nothing since we have hit the maximum number of machines
13161319 for _ in range (3 ):
1317- # scaling will do nothing since we have hit the maximum number of machines
13181320 await auto_scale_cluster (
13191321 app = initialized_app , auto_scaling_mode = DynamicAutoscaling ()
13201322 )
@@ -1328,6 +1330,46 @@ async def test_cluster_adapts_machines_on_the_fly(
13281330 instance_filters = instance_type_filters ,
13291331 )
13301332
1333+ # now we simulate that some of the services in the 1st batch have completed and that we are 1 below the max
1334+ # a machine should switch off and another type should be started
1335+ completed_services_to_stop = random .sample (
1336+ first_batch_services ,
1337+ scale_up_params1 .num_services
1338+ - app_settings .AUTOSCALING_EC2_INSTANCES .EC2_INSTANCES_MAX_INSTANCES
1339+ + 1 ,
1340+ )
1341+ await asyncio .gather (
1342+ * (
1343+ async_docker_client .services .delete (s .id )
1344+ for s in completed_services_to_stop
1345+ if s .id
1346+ )
1347+ )
1348+
1349+ for _ in range (3 ):
1350+ await auto_scale_cluster (
1351+ app = initialized_app , auto_scaling_mode = DynamicAutoscaling ()
1352+ )
1353+ all_instances = await ec2_client .describe_instances ()
1354+ assert len (all_instances ["Reservations" ]) == 2 , "there should be 2 Reservations"
1355+ reservation1 = all_instances ["Reservations" ][0 ]
1356+ assert "Instances" in reservation1
1357+ assert len (reservation1 ["Instances" ]) == (
1358+ app_settings .AUTOSCALING_EC2_INSTANCES .EC2_INSTANCES_MAX_INSTANCES - 1
1359+ ), f"expected { app_settings .AUTOSCALING_EC2_INSTANCES .EC2_INSTANCES_MAX_INSTANCES - 1 } EC2 instances, found { len (reservation1 ['Instances' ])} "
1360+ for instance in reservation1 ["Instances" ]:
1361+ assert "InstanceType" in instance
1362+ assert instance ["InstanceType" ] == scale_up_params1 .expected_instance_type
1363+
1364+ reservation2 = all_instances ["Reservations" ][0 ]
1365+ assert "Instances" in reservation2
1366+ assert len (reservation2 ["Instances" ]) == (
1367+ app_settings .AUTOSCALING_EC2_INSTANCES .EC2_INSTANCES_MAX_INSTANCES - 1
1368+ ), f"expected { app_settings .AUTOSCALING_EC2_INSTANCES .EC2_INSTANCES_MAX_INSTANCES - 1 } EC2 instances, found { len (reservation2 ['Instances' ])} "
1369+ for instance in reservation2 ["Instances" ]:
1370+ assert "InstanceType" in instance
1371+ assert instance ["InstanceType" ] == scale_up_params2 .expected_instance_type
1372+
13311373
13321374@pytest .mark .parametrize (
13331375 "docker_service_imposed_ec2_type, docker_service_ram, expected_ec2_type" ,
0 commit comments