Skip to content

Commit 2697b21

Browse files
keshav-chandakKeshav Chandak
and
Keshav Chandak
authored
fix: Cron expression resetting on update monitor (#3655)
Co-authored-by: Keshav Chandak <[email protected]>
1 parent 0ab3048 commit 2697b21

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

src/sagemaker/model_monitor/dataset_format.py

-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ def csv(header=True):
7171
Args:
7272
header (bool): Whether the csv dataset to baseline and monitor has a header.
7373
Default: True.
74-
output_columns_position (str): The position of the output columns.
75-
Must be one of ("START", "END"). Default: "START".
7674
7775
Returns:
7876
dict: JSON string containing DatasetFormat to be used by DefaultModelMonitor.

src/sagemaker/model_monitor/model_monitoring.py

+15
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,21 @@ def _update_data_quality_monitoring_schedule(
20592059
self._update_monitoring_schedule(self.job_definition_name, schedule_cron_expression)
20602060
return
20612061

2062+
existing_desc = self.sagemaker_session.describe_monitoring_schedule(
2063+
monitoring_schedule_name=self.monitoring_schedule_name
2064+
)
2065+
2066+
if (
2067+
existing_desc.get("MonitoringScheduleConfig") is not None
2068+
and existing_desc["MonitoringScheduleConfig"].get("ScheduleConfig") is not None
2069+
and existing_desc["MonitoringScheduleConfig"]["ScheduleConfig"]["ScheduleExpression"]
2070+
is not None
2071+
and schedule_cron_expression is None
2072+
):
2073+
schedule_cron_expression = existing_desc["MonitoringScheduleConfig"]["ScheduleConfig"][
2074+
"ScheduleExpression"
2075+
]
2076+
20622077
# Need to update schedule with a new job definition
20632078
job_desc = self.sagemaker_session.sagemaker_client.describe_data_quality_job_definition(
20642079
JobDefinitionName=self.job_definition_name

tests/integ/test_model_monitor.py

+47-1
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,49 @@ def test_default_monitor_create_and_update_schedule_config_without_customization
802802
_wait_for_schedule_changes_to_apply(monitor=my_default_monitor)
803803

804804

805+
@pytest.mark.skipif(
806+
tests.integ.test_region() in tests.integ.NO_MODEL_MONITORING_REGIONS,
807+
reason="ModelMonitoring is not yet supported in this region.",
808+
)
809+
def test_default_monitor_create_and_simple_update_schedule_config(sagemaker_session, predictor):
810+
my_default_monitor = DefaultModelMonitor(role=ROLE, sagemaker_session=sagemaker_session)
811+
812+
my_default_monitor.create_monitoring_schedule(
813+
endpoint_input=predictor.endpoint_name,
814+
schedule_cron_expression=CronExpressionGenerator.hourly(),
815+
)
816+
817+
schedule_description = my_default_monitor.describe_schedule()
818+
_verify_default_monitoring_schedule(
819+
sagemaker_session=sagemaker_session,
820+
schedule_description=schedule_description,
821+
cron_expression=CronExpressionGenerator.hourly(),
822+
)
823+
824+
_wait_for_schedule_changes_to_apply(my_default_monitor)
825+
826+
my_default_monitor.update_monitoring_schedule(
827+
max_runtime_in_seconds=UPDATED_MAX_RUNTIME_IN_SECONDS
828+
)
829+
830+
_wait_for_schedule_changes_to_apply(my_default_monitor)
831+
832+
schedule_description = my_default_monitor.describe_schedule()
833+
834+
_verify_default_monitoring_schedule(
835+
sagemaker_session=sagemaker_session,
836+
schedule_description=schedule_description,
837+
cron_expression=CronExpressionGenerator.hourly(),
838+
max_runtime_in_seconds=UPDATED_MAX_RUNTIME_IN_SECONDS,
839+
)
840+
841+
_wait_for_schedule_changes_to_apply(monitor=my_default_monitor)
842+
843+
my_default_monitor.stop_monitoring_schedule()
844+
845+
_wait_for_schedule_changes_to_apply(monitor=my_default_monitor)
846+
847+
805848
@pytest.mark.skipif(
806849
tests.integ.test_region() in tests.integ.NO_MODEL_MONITORING_REGIONS,
807850
reason="ModelMonitoring is not yet supported in this region.",
@@ -1644,7 +1687,10 @@ def _verify_default_monitoring_schedule(
16441687
schedule_description["MonitoringScheduleConfig"]["ScheduleConfig"]["ScheduleExpression"]
16451688
== cron_expression
16461689
)
1647-
assert schedule_description["MonitoringType"] == "DataQuality"
1690+
if schedule_description.get("MonitoringType") is not None:
1691+
assert schedule_description["MonitoringType"] == "DataQuality"
1692+
else:
1693+
assert schedule_description["MonitoringScheduleConfig"]["MonitoringType"] == "DataQuality"
16481694
job_definition_name = schedule_description["MonitoringScheduleConfig"].get(
16491695
"MonitoringJobDefinitionName"
16501696
)

tests/unit/sagemaker/monitor/test_model_monitoring.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
PROBLEM_TYPE = "Regression"
6767
GROUND_TRUTH_ATTRIBUTE = "TestAttribute"
6868

69-
69+
CRON_DAILY = CronExpressionGenerator.daily()
7070
BASELINING_JOB_NAME = "baselining-job"
7171
BASELINE_DATASET_PATH = "/my/local/path/baseline.csv"
7272
PREPROCESSOR_PATH = "/my/local/path/preprocessor.py"
@@ -85,7 +85,9 @@
8585
MONITORING_SCHEDULE_DESC = {
8686
"MonitoringScheduleArn": "arn:aws:monitoring-schedule",
8787
"MonitoringScheduleName": "my-monitoring-schedule",
88+
"MonitoringScheduleStatus": "Completed",
8889
"MonitoringScheduleConfig": {
90+
"ScheduleExpression": CRON_DAILY,
8991
"MonitoringJobDefinition": {
9092
"MonitoringOutputConfig": {},
9193
"MonitoringResources": {
@@ -102,7 +104,7 @@
102104
],
103105
},
104106
"RoleArn": ROLE,
105-
}
107+
},
106108
},
107109
"EndpointName": "my-endpoint",
108110
}
@@ -284,7 +286,6 @@
284286
security_group_ids=NEW_SECURITY_GROUP_IDS,
285287
subnets=NEW_SUBNETS,
286288
)
287-
CRON_DAILY = CronExpressionGenerator.daily()
288289
NEW_ENDPOINT_NAME = "new-endpoint"
289290
NEW_GROUND_TRUTH_S3_URI = "s3://bucket/monitoring_captured/groundtruth"
290291
NEW_START_TIME_OFFSET = "-PT2H"
@@ -893,6 +894,7 @@ def _test_data_quality_monitor_update_schedule(data_quality_monitor, sagemaker_s
893894
)
894895
sagemaker_session.sagemaker_client.create_data_quality_job_definition = Mock()
895896
sagemaker_session.expand_role = Mock(return_value=NEW_ROLE_ARN)
897+
sagemaker_session.describe_monitoring_schedule = Mock(return_value=MONITORING_SCHEDULE_DESC)
896898
old_job_definition_name = data_quality_monitor.job_definition_name
897899
data_quality_monitor.update_monitoring_schedule(role=NEW_ROLE_ARN)
898900
expected_arguments = {

0 commit comments

Comments
 (0)