Skip to content

Commit e152806

Browse files
authored
test: xfail CI Health V2 tests on GPU capacity shortages (#6396)
* test: xfail CI Health V2 tests on GPU capacity shortages test_predict_stream deploys a falcon-7b LMI endpoint on ml.g5.2xlarge in its module fixture. When us-west-2 has no capacity, the deploy fails with InsufficientInstanceCapacity, the test errors at setup, and pytest-rerunfailures retries the ~30 minute deploy several times. Mark it as an expected failure instead, matching the JumpStart integ tests. test_model_package_arn_jumpstart_model already imports x_fail_if_ice but was missing the decorator, so ml.g4dn.2xlarge capacity shortages failed the slow-tests-v2 job. Apply the decorator. * fix: stop live-logging endpoint wait from hanging on early failure session._live_logging_deploy_done returned None whenever the endpoint's CloudWatch log group was missing, even after the endpoint had left Creating. The log group only exists once a container starts, so an endpoint that fails before provisioning (InsufficientInstanceCapacity, a missing model) was polled forever. ModelBuilder enables endpoint logging by default, so test_serverless_deployment hung the PR integ build until the CodeBuild timeout. Return the describe response once the endpoint is no longer in progress, as sagemaker-core already does. Also fix the integ flakes from the same build: - test_base_model_builder_deploy: use a unique model name per fixture so one xdist worker's cleanup cannot delete the model another worker's endpoint is being created from. - create_and_execute_pipeline: raise the default wait from 400s to 1000s; two sequential function steps took ~470s. - test_jumpstart_transfer_learning_estimator_class: xfail on InsufficientInstanceCapacity for ml.g4dn.xlarge.
1 parent ad2fc17 commit e152806

7 files changed

Lines changed: 87 additions & 8 deletions

File tree

‎src/sagemaker/session.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8965,6 +8965,12 @@ def _live_logging_deploy_done(sagemaker_client, endpoint_name, paginator, pagina
89658965
return desc
89668966
except ClientError as e:
89678967
if e.response["Error"]["Code"] == "ResourceNotFoundException":
8968+
# The log group only exists once a container has started, so an endpoint
8969+
# that fails before any instance is provisioned (e.g. on
8970+
# InsufficientInstanceCapacity, or a missing model) never gets one. A missing
8971+
# log group must not keep an already finished deployment waiting forever.
8972+
if stop:
8973+
return desc
89688974
LOGGER.debug("Waiting for endpoint log group to appear")
89698975
return None
89708976
raise e

‎tests/integ/sagemaker/jumpstart/model/test_jumpstart_model.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def test_prepacked_jumpstart_model(setup):
112112
tests.integ.test_region() not in GATED_INFERENCE_MODEL_PACKAGE_SUPPORTED_REGIONS,
113113
reason=f"JumpStart model package inference models unavailable in {tests.integ.test_region()}.",
114114
)
115+
@x_fail_if_ice
115116
def test_model_package_arn_jumpstart_model(setup):
116117

117118
model_id = "meta-textgeneration-llama-2-7b"

‎tests/integ/sagemaker/jumpstart/script_mode_class/test_transfer_learning.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@
4646
EndpointInvoker,
4747
get_sm_session,
4848
get_training_dataset_for_model_and_version,
49+
x_fail_if_ice,
4950
)
5051

5152

53+
@x_fail_if_ice
5254
def test_jumpstart_transfer_learning_estimator_class(setup):
5355

5456
model_id, model_version = "huggingface-spc-bert-base-cased", "1.2.3"

‎tests/integ/sagemaker/serve/test_base_model_builder_deploy.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,11 @@ def invoke(self, input_object: object, model: object):
170170
training_job.wait()
171171

172172
xgboost_model_builder = ModelBuilder(
173-
name="ModelBuilderTest",
173+
# Unique per fixture instance: xdist runs this module's tests on separate
174+
# workers, and each test's cleanup deletes the model. A shared fixed name
175+
# let one worker delete the model another worker's endpoint was being
176+
# created from ("Model ... does not exist").
177+
name=f"ModelBuilderTest-{uuid.uuid4().hex[:8]}",
174178
model_path=training_job.model_artifacts.s3_model_artifacts,
175179
role_arn=role,
176180
inference_spec=XGBoostSpec(),

‎tests/integ/sagemaker/workflow/helpers.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ def create_and_execute_pipeline(
3838
step_status,
3939
step_result_type=None,
4040
step_result_value=None,
41-
wait_duration=400, # seconds
41+
# Two sequential function steps routinely take ~8 minutes when each step's
42+
# instance spends ~3 minutes in Starting, so 400s was too tight.
43+
wait_duration=1000, # seconds
4244
selective_execution_config=None,
4345
):
4446
create_arn = None

‎tests/integ/test_predict_stream.py‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import tests.integ.timeout
2121

2222
from sagemaker import image_uris
23+
from sagemaker.exceptions import UnexpectedStatusException
2324
from sagemaker.iterators import LineIterator
2425
from sagemaker.model import Model
2526
from sagemaker.predictor import Predictor
@@ -56,12 +57,21 @@ def endpoint_name(sagemaker_session):
5657
name=lmi_endpoint_name, # model name
5758
role=ROLE,
5859
)
59-
lmi_model.deploy(
60-
INSTANCE_COUNT,
61-
INSTANCE_TYPE,
62-
endpoint_name=lmi_endpoint_name,
63-
container_startup_health_check_timeout=900,
64-
)
60+
try:
61+
lmi_model.deploy(
62+
INSTANCE_COUNT,
63+
INSTANCE_TYPE,
64+
endpoint_name=lmi_endpoint_name,
65+
container_startup_health_check_timeout=900,
66+
)
67+
except UnexpectedStatusException as e:
68+
# Insufficient ml.g5.2xlarge capacity is a transient, region-level AWS
69+
# condition, not a SDK defect. Mark it as an expected failure so the
70+
# canary doesn't go red, and so pytest-rerunfailures doesn't retry a
71+
# ~30 minute deploy that is unlikely to get capacity on retry.
72+
if "InsufficientInstanceCapacity" in str(e):
73+
pytest.xfail(str(e))
74+
raise
6575
yield lmi_endpoint_name
6676

6777

‎tests/unit/test_session.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7374,3 +7374,57 @@ def test_get_most_recently_created_approved_model_package(sagemaker_session):
73747374
model_package.model_package_arn
73757375
== "arn:aws:sagemaker:us-west-2:123456789012:model-package/model-version/3"
73767376
)
7377+
7378+
7379+
def _log_group_not_found():
7380+
return ClientError(
7381+
{"Error": {"Code": "ResourceNotFoundException", "Message": "log group not found"}},
7382+
"FilterLogEvents",
7383+
)
7384+
7385+
7386+
@patch("sagemaker.session.time.sleep")
7387+
def test_live_logging_deploy_done_returns_failed_endpoint_without_log_group(sleep):
7388+
# An endpoint that fails before any container starts never gets a log group.
7389+
# The wait must stop instead of polling for the log group forever.
7390+
desc = {"EndpointStatus": "Failed", "FailureReason": "InsufficientInstanceCapacity"}
7391+
sagemaker_client = Mock(describe_endpoint=Mock(return_value=desc))
7392+
paginator = Mock(paginate=Mock(side_effect=_log_group_not_found()))
7393+
7394+
result = sagemaker.session._live_logging_deploy_done(
7395+
sagemaker_client, "my-endpoint", paginator, {}, poll=5
7396+
)
7397+
7398+
assert result == desc
7399+
sleep.assert_called_once_with(5)
7400+
7401+
7402+
@patch("sagemaker.session.time.sleep")
7403+
def test_live_logging_deploy_done_keeps_waiting_for_creating_endpoint_without_log_group(sleep):
7404+
sagemaker_client = Mock(describe_endpoint=Mock(return_value={"EndpointStatus": "Creating"}))
7405+
paginator = Mock(paginate=Mock(side_effect=_log_group_not_found()))
7406+
7407+
result = sagemaker.session._live_logging_deploy_done(
7408+
sagemaker_client, "my-endpoint", paginator, {}, poll=5
7409+
)
7410+
7411+
assert result is None
7412+
sleep.assert_not_called()
7413+
7414+
7415+
def test_wait_for_endpoint_live_logging_raises_on_failed_endpoint_without_log_group(
7416+
sagemaker_session,
7417+
):
7418+
failed = {"EndpointStatus": "Failed", "FailureReason": "Model does not exist."}
7419+
# Bound the polls so a regression fails the test instead of hanging it.
7420+
sagemaker_session.sagemaker_client.describe_endpoint = Mock(
7421+
side_effect=[failed] * 3 + [AssertionError("wait_for_endpoint kept polling")]
7422+
)
7423+
logs_client = Mock()
7424+
logs_client.get_paginator.return_value.paginate.side_effect = _log_group_not_found()
7425+
sagemaker_session.boto_session.client = Mock(return_value=logs_client)
7426+
7427+
with patch("sagemaker.session._has_permission_for_live_logging", return_value=True):
7428+
with patch("sagemaker.session.time.sleep"):
7429+
with pytest.raises(exceptions.UnexpectedStatusException, match="Model does not exist"):
7430+
sagemaker_session.wait_for_endpoint("my-endpoint", live_logging=True)

0 commit comments

Comments
 (0)