Skip to content

Commit 677d42d

Browse files
rsareddy0329Roja Reddy Sareddy
andauthored
fix(model-monitor): honor base_job_name for job definition names (#6372)
ModelMonitor subclasses generated the monitoring job definition name from the type's JOB_DEFINITION_BASE_NAME constant, ignoring a user-supplied base_job_name -- even though the monitoring schedule name already honors it. As a result base_job_name was silently dropped for the job definition (and the monitoring resources derived from it). Add a _generate_job_definition_name() helper on the ModelMonitor base (mirroring _generate_monitoring_schedule_name) that uses base_job_name when provided and falls back to JOB_DEFINITION_BASE_NAME otherwise, and use it in the data-quality, model-quality, model-bias and model-explainability create and update paths. Note: the recurring execution processing job names are assigned by the SageMaker service and remain non-customizable. Relates-to #4783 Co-authored-by: Roja Reddy Sareddy <rsareddy@amazon.com>
1 parent e449c7f commit 677d42d

3 files changed

Lines changed: 73 additions & 9 deletions

File tree

‎sagemaker-core/src/sagemaker/core/model_monitor/clarify_model_monitoring.py‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from sagemaker.core import image_uris, s3
3232
from sagemaker.core.helper.session_helper import Session, expand_role
3333
from sagemaker.core.common_utils import (
34-
name_from_base,
3534
format_tags,
3635
get_resource_name_from_arn,
3736
list_tags,
@@ -640,7 +639,7 @@ def create_monitoring_schedule(
640639
monitor_schedule_name = self._generate_monitoring_schedule_name(
641640
schedule_name=monitor_schedule_name
642641
)
643-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
642+
new_job_definition_name = self._generate_job_definition_name()
644643
request_dict = self._build_create_job_definition_request(
645644
monitoring_schedule_name=monitor_schedule_name,
646645
job_definition_name=new_job_definition_name,
@@ -783,7 +782,7 @@ def update_monitoring_schedule(
783782
job_desc = self.sagemaker_session.sagemaker_client.describe_model_bias_job_definition(
784783
JobDefinitionName=self.job_definition_name
785784
)
786-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
785+
new_job_definition_name = self._generate_job_definition_name()
787786
request_dict = self._build_create_job_definition_request(
788787
monitoring_schedule_name=self.monitoring_schedule_name,
789788
job_definition_name=new_job_definition_name,
@@ -1082,7 +1081,7 @@ def create_monitoring_schedule(
10821081
monitor_schedule_name = self._generate_monitoring_schedule_name(
10831082
schedule_name=monitor_schedule_name
10841083
)
1085-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
1084+
new_job_definition_name = self._generate_job_definition_name()
10861085
request_dict = self._build_create_job_definition_request(
10871086
monitoring_schedule_name=monitor_schedule_name,
10881087
job_definition_name=new_job_definition_name,
@@ -1230,7 +1229,7 @@ def update_monitoring_schedule(
12301229
JobDefinitionName=self.job_definition_name
12311230
)
12321231
)
1233-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
1232+
new_job_definition_name = self._generate_job_definition_name()
12341233
request_dict = self._build_create_job_definition_request(
12351234
monitoring_schedule_name=self.monitoring_schedule_name,
12361235
job_definition_name=new_job_definition_name,

‎sagemaker-core/src/sagemaker/core/model_monitor/model_monitoring.py‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,22 @@ def _generate_monitoring_schedule_name(self, schedule_name=None):
12131213

12141214
return name_from_base(base=base_name)
12151215

1216+
def _generate_job_definition_name(self):
1217+
"""Generate the monitoring job definition name.
1218+
1219+
Uses the base name given to the constructor when provided, so a
1220+
user-supplied ``base_job_name`` is reflected in the job definition
1221+
name (and the monitoring resources derived from it) rather than being
1222+
silently ignored (see #4783); otherwise falls back to the monitor
1223+
type's default base name (``JOB_DEFINITION_BASE_NAME``).
1224+
1225+
Returns:
1226+
str: The generated job definition name.
1227+
1228+
"""
1229+
base_name = self.base_job_name or self.JOB_DEFINITION_BASE_NAME
1230+
return name_from_base(base=base_name)
1231+
12161232
@staticmethod
12171233
def _generate_env_map(
12181234
env,
@@ -2074,7 +2090,7 @@ def create_monitoring_schedule(
20742090
monitor_schedule_name = self._generate_monitoring_schedule_name(
20752091
schedule_name=monitor_schedule_name
20762092
)
2077-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
2093+
new_job_definition_name = self._generate_job_definition_name()
20782094
request_dict = self._build_create_data_quality_job_definition_request(
20792095
monitoring_schedule_name=monitor_schedule_name,
20802096
job_definition_name=new_job_definition_name,
@@ -2444,7 +2460,7 @@ def _update_data_quality_monitoring_schedule(
24442460
job_desc = self.sagemaker_session.sagemaker_client.describe_data_quality_job_definition(
24452461
JobDefinitionName=self.job_definition_name
24462462
)
2447-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
2463+
new_job_definition_name = self._generate_job_definition_name()
24482464
request_dict = self._build_create_data_quality_job_definition_request(
24492465
monitoring_schedule_name=self.monitoring_schedule_name,
24502466
job_definition_name=new_job_definition_name,
@@ -3208,7 +3224,7 @@ def create_monitoring_schedule(
32083224
monitor_schedule_name = self._generate_monitoring_schedule_name(
32093225
schedule_name=monitor_schedule_name
32103226
)
3211-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
3227+
new_job_definition_name = self._generate_job_definition_name()
32123228
request_dict = self._build_create_model_quality_job_definition_request(
32133229
monitoring_schedule_name=monitor_schedule_name,
32143230
job_definition_name=new_job_definition_name,
@@ -3364,7 +3380,7 @@ def update_monitoring_schedule(
33643380
job_desc = self.sagemaker_session.sagemaker_client.describe_model_quality_job_definition(
33653381
JobDefinitionName=self.job_definition_name
33663382
)
3367-
new_job_definition_name = name_from_base(self.JOB_DEFINITION_BASE_NAME)
3383+
new_job_definition_name = self._generate_job_definition_name()
33683384
request_dict = self._build_create_model_quality_job_definition_request(
33693385
monitoring_schedule_name=self.monitoring_schedule_name,
33703386
job_definition_name=new_job_definition_name,

‎sagemaker-core/tests/unit/test_model_monitoring.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,55 @@ def test_generate_baselining_job_name_with_custom_name(self, mock_session, test_
380380
job_name = monitor._generate_baselining_job_name(job_name="custom-job")
381381
assert job_name == "custom-job"
382382

383+
def test_generate_job_definition_name_uses_base_job_name(self, mock_session, test_role):
384+
"""A user-supplied base_job_name is reflected in the job definition name (#4783)."""
385+
with (
386+
patch(
387+
"sagemaker.core.model_monitor.model_monitoring.resolve_value_from_config",
388+
side_effect=lambda x, *args, **kwargs: x,
389+
),
390+
patch(
391+
"sagemaker.core.model_monitor.model_monitoring.resolve_class_attribute_from_config",
392+
return_value=None,
393+
),
394+
patch(
395+
"sagemaker.core.model_monitor.model_monitoring."
396+
"DefaultModelMonitor._get_default_image_uri",
397+
return_value="test-image",
398+
),
399+
):
400+
monitor = DefaultModelMonitor(
401+
role=test_role,
402+
sagemaker_session=mock_session,
403+
base_job_name="my-monitor",
404+
)
405+
name = monitor._generate_job_definition_name()
406+
assert name.startswith("my-monitor-")
407+
assert DefaultModelMonitor.JOB_DEFINITION_BASE_NAME not in name
408+
409+
def test_generate_job_definition_name_defaults_without_base_job_name(
410+
self, mock_session, test_role
411+
):
412+
"""Without base_job_name, the job definition name falls back to the type default."""
413+
with (
414+
patch(
415+
"sagemaker.core.model_monitor.model_monitoring.resolve_value_from_config",
416+
side_effect=lambda x, *args, **kwargs: x,
417+
),
418+
patch(
419+
"sagemaker.core.model_monitor.model_monitoring.resolve_class_attribute_from_config",
420+
return_value=None,
421+
),
422+
patch(
423+
"sagemaker.core.model_monitor.model_monitoring."
424+
"DefaultModelMonitor._get_default_image_uri",
425+
return_value="test-image",
426+
),
427+
):
428+
monitor = DefaultModelMonitor(role=test_role, sagemaker_session=mock_session)
429+
name = monitor._generate_job_definition_name()
430+
assert name.startswith(DefaultModelMonitor.JOB_DEFINITION_BASE_NAME)
431+
383432
def test_start_monitoring_schedule(self, mock_session, test_role):
384433
with (
385434
patch(

0 commit comments

Comments
 (0)