mlrun 1.8.0rc4__py3-none-any.whl → 1.8.0rc7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +5 -3
- mlrun/alerts/alert.py +129 -2
- mlrun/artifacts/__init__.py +1 -1
- mlrun/artifacts/base.py +12 -1
- mlrun/artifacts/document.py +59 -38
- mlrun/common/constants.py +1 -0
- mlrun/common/model_monitoring/__init__.py +0 -2
- mlrun/common/model_monitoring/helpers.py +0 -28
- mlrun/common/schemas/__init__.py +2 -4
- mlrun/common/schemas/alert.py +80 -1
- mlrun/common/schemas/artifact.py +4 -0
- mlrun/common/schemas/client_spec.py +0 -1
- mlrun/common/schemas/model_monitoring/__init__.py +0 -6
- mlrun/common/schemas/model_monitoring/constants.py +11 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
- mlrun/common/schemas/notification.py +6 -0
- mlrun/common/schemas/project.py +3 -0
- mlrun/config.py +2 -3
- mlrun/datastore/datastore_profile.py +57 -17
- mlrun/datastore/sources.py +1 -2
- mlrun/datastore/vectorstore.py +67 -59
- mlrun/db/base.py +29 -19
- mlrun/db/factory.py +0 -3
- mlrun/db/httpdb.py +224 -161
- mlrun/db/nopdb.py +36 -17
- mlrun/execution.py +46 -32
- mlrun/feature_store/api.py +1 -0
- mlrun/model.py +7 -0
- mlrun/model_monitoring/__init__.py +3 -2
- mlrun/model_monitoring/api.py +55 -53
- mlrun/model_monitoring/applications/_application_steps.py +4 -2
- mlrun/model_monitoring/applications/base.py +165 -6
- mlrun/model_monitoring/applications/context.py +88 -37
- mlrun/model_monitoring/applications/evidently_base.py +0 -1
- mlrun/model_monitoring/applications/histogram_data_drift.py +3 -7
- mlrun/model_monitoring/controller.py +43 -37
- mlrun/model_monitoring/db/__init__.py +0 -2
- mlrun/model_monitoring/db/tsdb/base.py +2 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
- mlrun/model_monitoring/helpers.py +79 -66
- mlrun/model_monitoring/stream_processing.py +83 -270
- mlrun/model_monitoring/writer.py +1 -10
- mlrun/projects/pipelines.py +37 -1
- mlrun/projects/project.py +171 -74
- mlrun/run.py +40 -0
- mlrun/runtimes/nuclio/function.py +7 -6
- mlrun/runtimes/nuclio/serving.py +9 -2
- mlrun/serving/routers.py +158 -145
- mlrun/serving/server.py +6 -0
- mlrun/serving/states.py +21 -7
- mlrun/serving/v2_serving.py +70 -61
- mlrun/utils/helpers.py +14 -30
- mlrun/utils/notifications/notification/mail.py +36 -9
- mlrun/utils/notifications/notification_pusher.py +43 -18
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/METADATA +5 -4
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/RECORD +62 -75
- mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
- mlrun/model_monitoring/db/stores/__init__.py +0 -136
- mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
- mlrun/model_monitoring/db/stores/base/store.py +0 -154
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
- mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
- mlrun/model_monitoring/model_endpoint.py +0 -120
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/top_level.txt +0 -0
mlrun/serving/v2_serving.py
CHANGED
|
@@ -21,10 +21,9 @@ import mlrun.artifacts
|
|
|
21
21
|
import mlrun.common.model_monitoring.helpers
|
|
22
22
|
import mlrun.common.schemas.model_monitoring
|
|
23
23
|
import mlrun.model_monitoring
|
|
24
|
-
from mlrun.errors import err_to_str
|
|
25
24
|
from mlrun.utils import logger, now_date
|
|
26
25
|
|
|
27
|
-
from ..common.
|
|
26
|
+
from ..common.schemas.model_monitoring import ModelEndpointSchema
|
|
28
27
|
from .server import GraphServer
|
|
29
28
|
from .utils import StepToDict, _extract_input_data, _update_result_body
|
|
30
29
|
|
|
@@ -110,12 +109,6 @@ class V2ModelServer(StepToDict):
|
|
|
110
109
|
self._result_path = result_path
|
|
111
110
|
self._kwargs = kwargs # for to_dict()
|
|
112
111
|
self._params = kwargs
|
|
113
|
-
self._model_logger = (
|
|
114
|
-
_ModelLogPusher(self, context)
|
|
115
|
-
if context and context.stream.enabled
|
|
116
|
-
else None
|
|
117
|
-
)
|
|
118
|
-
|
|
119
112
|
self.metrics = {}
|
|
120
113
|
self.labels = {}
|
|
121
114
|
self.model = None
|
|
@@ -125,6 +118,7 @@ class V2ModelServer(StepToDict):
|
|
|
125
118
|
self._versioned_model_name = None
|
|
126
119
|
self.model_endpoint_uid = None
|
|
127
120
|
self.shard_by_endpoint = shard_by_endpoint
|
|
121
|
+
self._model_logger = None
|
|
128
122
|
|
|
129
123
|
def _load_and_update_state(self):
|
|
130
124
|
try:
|
|
@@ -157,6 +151,11 @@ class V2ModelServer(StepToDict):
|
|
|
157
151
|
self.model_endpoint_uid = _init_endpoint_record(
|
|
158
152
|
graph_server=server, model=self
|
|
159
153
|
)
|
|
154
|
+
self._model_logger = (
|
|
155
|
+
_ModelLogPusher(self, self.context)
|
|
156
|
+
if self.context and self.context.stream.enabled
|
|
157
|
+
else None
|
|
158
|
+
)
|
|
160
159
|
|
|
161
160
|
def get_param(self, key: str, default=None):
|
|
162
161
|
"""get param by key (specified in the model or the function)"""
|
|
@@ -474,7 +473,7 @@ class V2ModelServer(StepToDict):
|
|
|
474
473
|
|
|
475
474
|
|
|
476
475
|
class _ModelLogPusher:
|
|
477
|
-
def __init__(self, model, context, output_stream=None):
|
|
476
|
+
def __init__(self, model: V2ModelServer, context, output_stream=None):
|
|
478
477
|
self.model = model
|
|
479
478
|
self.verbose = context.verbose
|
|
480
479
|
self.hostname = context.stream.hostname
|
|
@@ -496,6 +495,7 @@ class _ModelLogPusher:
|
|
|
496
495
|
"version": self.model.version,
|
|
497
496
|
"host": self.hostname,
|
|
498
497
|
"function_uri": self.function_uri,
|
|
498
|
+
"endpoint_id": self.model.model_endpoint_uid,
|
|
499
499
|
}
|
|
500
500
|
if getattr(self.model, "labels", None):
|
|
501
501
|
base_data["labels"] = self.model.labels
|
|
@@ -567,26 +567,13 @@ def _init_endpoint_record(
|
|
|
567
567
|
"""
|
|
568
568
|
|
|
569
569
|
logger.info("Initializing endpoint records")
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
try:
|
|
573
|
-
# Getting project name from the function uri
|
|
574
|
-
project, uri, tag, hash_key = parse_versioned_object_uri(
|
|
575
|
-
graph_server.function_uri
|
|
576
|
-
)
|
|
577
|
-
except Exception as e:
|
|
578
|
-
logger.error("Failed to parse function URI", exc=err_to_str(e))
|
|
579
|
-
return None
|
|
580
|
-
|
|
581
|
-
# Generating model endpoint ID based on function uri and model version
|
|
582
|
-
uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
|
|
583
|
-
function_uri=graph_server.function_uri,
|
|
584
|
-
versioned_model=model.versioned_model_name,
|
|
585
|
-
).uid
|
|
586
|
-
|
|
570
|
+
if not model.model_spec:
|
|
571
|
+
model.get_model()
|
|
587
572
|
try:
|
|
588
573
|
model_ep = mlrun.get_run_db().get_model_endpoint(
|
|
589
|
-
project=project,
|
|
574
|
+
project=graph_server.project,
|
|
575
|
+
name=model.name,
|
|
576
|
+
function_name=graph_server.function_name,
|
|
590
577
|
)
|
|
591
578
|
except mlrun.errors.MLRunNotFoundError:
|
|
592
579
|
model_ep = None
|
|
@@ -596,62 +583,84 @@ def _init_endpoint_record(
|
|
|
596
583
|
)
|
|
597
584
|
return
|
|
598
585
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
586
|
+
function = mlrun.get_run_db().get_function(
|
|
587
|
+
name=graph_server.function_name,
|
|
588
|
+
project=graph_server.project,
|
|
589
|
+
tag=graph_server.function_tag or "latest",
|
|
590
|
+
)
|
|
591
|
+
function_uid = function.get("metadata", {}).get("uid")
|
|
592
|
+
if not model_ep and model.context.server.track_models:
|
|
593
|
+
logger.info(
|
|
594
|
+
"Creating a new model endpoint record",
|
|
595
|
+
name=model.name,
|
|
596
|
+
project=graph_server.project,
|
|
597
|
+
function_name=graph_server.function_name,
|
|
598
|
+
function_uid=function_uid,
|
|
599
|
+
model_name=model.model_spec.metadata.key,
|
|
600
|
+
model_uid=model.model_spec.metadata.uid,
|
|
601
|
+
model_class=model.__class__.__name__,
|
|
602
|
+
model_tag=model.model_spec.tag,
|
|
603
|
+
)
|
|
604
|
+
model_ep = mlrun.common.schemas.ModelEndpoint(
|
|
602
605
|
metadata=mlrun.common.schemas.ModelEndpointMetadata(
|
|
603
|
-
project=project,
|
|
606
|
+
project=graph_server.project,
|
|
607
|
+
labels=model.model_spec.labels,
|
|
608
|
+
name=model.name,
|
|
609
|
+
endpoint_type=mlrun.common.schemas.model_monitoring.EndpointType.NODE_EP,
|
|
604
610
|
),
|
|
605
611
|
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
606
|
-
|
|
607
|
-
|
|
612
|
+
function_name=graph_server.function_name,
|
|
613
|
+
function_uid=function_uid,
|
|
614
|
+
function_tag=graph_server.function_tag or "latest",
|
|
615
|
+
model_name=model.model_spec.metadata.key,
|
|
616
|
+
model_uid=model.model_spec.metadata.uid,
|
|
608
617
|
model_class=model.__class__.__name__,
|
|
609
|
-
model_uri=model.model_path,
|
|
610
|
-
stream_path=model.context.stream.stream_uri,
|
|
611
|
-
active=True,
|
|
612
|
-
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled,
|
|
613
618
|
),
|
|
614
619
|
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
615
|
-
|
|
620
|
+
monitoring_mode=mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
621
|
+
if model.context.server.track_models
|
|
622
|
+
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled,
|
|
616
623
|
),
|
|
617
624
|
)
|
|
618
|
-
|
|
619
625
|
db = mlrun.get_run_db()
|
|
620
|
-
db.create_model_endpoint(
|
|
621
|
-
project=project,
|
|
622
|
-
endpoint_id=uid,
|
|
623
|
-
model_endpoint=model_endpoint.dict(),
|
|
624
|
-
)
|
|
626
|
+
db.create_model_endpoint(model_endpoint=model_ep)
|
|
625
627
|
|
|
626
628
|
elif model_ep:
|
|
627
629
|
attributes = {}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
630
|
+
if function_uid != model_ep.spec.function_uid:
|
|
631
|
+
attributes[ModelEndpointSchema.FUNCTION_UID] = function_uid
|
|
632
|
+
if model.model_spec.metadata.key != model_ep.spec.model_name:
|
|
633
|
+
attributes[ModelEndpointSchema.MODEL_NAME] = model.model_spec.metadata.key
|
|
634
|
+
if model.model_spec.metadata.uid != model_ep.spec.model_uid:
|
|
635
|
+
attributes[ModelEndpointSchema.MODEL_UID] = model.model_spec.metadata.uid
|
|
636
|
+
if model.__class__.__name__ != model_ep.spec.model_class:
|
|
637
|
+
attributes[ModelEndpointSchema.MODEL_CLASS] = model.__class__.__name__
|
|
635
638
|
if (
|
|
636
|
-
model_ep.
|
|
639
|
+
model_ep.status.monitoring_mode
|
|
637
640
|
== mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
638
641
|
) != model.context.server.track_models:
|
|
639
|
-
attributes[
|
|
642
|
+
attributes[ModelEndpointSchema.MONITORING_MODE] = (
|
|
640
643
|
mlrun.common.schemas.model_monitoring.ModelMonitoringMode.enabled
|
|
641
644
|
if model.context.server.track_models
|
|
642
645
|
else mlrun.common.schemas.model_monitoring.ModelMonitoringMode.disabled
|
|
643
646
|
)
|
|
644
647
|
if attributes:
|
|
645
|
-
db = mlrun.get_run_db()
|
|
646
|
-
db.patch_model_endpoint(
|
|
647
|
-
project=project,
|
|
648
|
-
endpoint_id=uid,
|
|
649
|
-
attributes=attributes,
|
|
650
|
-
)
|
|
651
648
|
logger.info(
|
|
652
649
|
"Updating model endpoint attributes",
|
|
653
650
|
attributes=attributes,
|
|
654
|
-
|
|
651
|
+
project=model_ep.metadata.project,
|
|
652
|
+
name=model_ep.metadata.name,
|
|
653
|
+
function_name=model_ep.spec.function_name,
|
|
654
|
+
)
|
|
655
|
+
db = mlrun.get_run_db()
|
|
656
|
+
model_ep = db.patch_model_endpoint(
|
|
657
|
+
project=model_ep.metadata.project,
|
|
658
|
+
name=model_ep.metadata.name,
|
|
659
|
+
function_name=model_ep.spec.function_name,
|
|
660
|
+
endpoint_id=model_ep.metadata.uid,
|
|
661
|
+
attributes=attributes,
|
|
655
662
|
)
|
|
663
|
+
else:
|
|
664
|
+
return None
|
|
656
665
|
|
|
657
|
-
return uid
|
|
666
|
+
return model_ep.metadata.uid
|
mlrun/utils/helpers.py
CHANGED
|
@@ -956,36 +956,6 @@ def fill_function_hash(function_dict, tag=""):
|
|
|
956
956
|
return fill_object_hash(function_dict, "hash", tag)
|
|
957
957
|
|
|
958
958
|
|
|
959
|
-
def fill_model_endpoint_hash(
|
|
960
|
-
model_endpoint: mlrun.common.schemas.ModelEndpointV2,
|
|
961
|
-
created_time: typing.Union[str, datetime],
|
|
962
|
-
) -> str:
|
|
963
|
-
"""
|
|
964
|
-
Fill the model endpoint uid field in the model endpoint object and returns it.
|
|
965
|
-
The uid is generated by hashing the following model endpoint fields:
|
|
966
|
-
- name
|
|
967
|
-
- model_tag
|
|
968
|
-
- function_name
|
|
969
|
-
- project
|
|
970
|
-
- created_time
|
|
971
|
-
"""
|
|
972
|
-
|
|
973
|
-
name = model_endpoint.metadata.name
|
|
974
|
-
model_tag = model_endpoint.spec.model_tag
|
|
975
|
-
function_name = model_endpoint.spec.function_name
|
|
976
|
-
project = model_endpoint.metadata.project
|
|
977
|
-
created_time = (
|
|
978
|
-
created_time
|
|
979
|
-
if isinstance(created_time, str)
|
|
980
|
-
else created_time.isoformat(sep=" ", timespec="microseconds")
|
|
981
|
-
)
|
|
982
|
-
|
|
983
|
-
unique_string = f"{name}_{model_tag}_{function_name}_{project}_{created_time}"
|
|
984
|
-
uid = hashlib.sha1(unique_string.encode("utf-8")).hexdigest()
|
|
985
|
-
model_endpoint.metadata.uid = uid
|
|
986
|
-
return uid
|
|
987
|
-
|
|
988
|
-
|
|
989
959
|
def retry_until_successful(
|
|
990
960
|
backoff: int, timeout: int, logger, verbose: bool, _function, *args, **kwargs
|
|
991
961
|
):
|
|
@@ -1886,3 +1856,17 @@ def run_with_retry(
|
|
|
1886
1856
|
if attempt == retry_count:
|
|
1887
1857
|
raise
|
|
1888
1858
|
raise last_exception
|
|
1859
|
+
|
|
1860
|
+
|
|
1861
|
+
def join_urls(base_url: Optional[str], path: Optional[str]) -> str:
|
|
1862
|
+
"""
|
|
1863
|
+
Joins a base URL with a path, ensuring proper handling of slashes.
|
|
1864
|
+
|
|
1865
|
+
:param base_url: The base URL (e.g., "http://example.com").
|
|
1866
|
+
:param path: The path to append to the base URL (e.g., "/path/to/resource").
|
|
1867
|
+
|
|
1868
|
+
:return: A unified URL with exactly one slash between base_url and path.
|
|
1869
|
+
"""
|
|
1870
|
+
if base_url is None:
|
|
1871
|
+
base_url = ""
|
|
1872
|
+
return f"{base_url.rstrip('/')}/{path.lstrip('/')}" if path else base_url
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import re
|
|
15
15
|
import typing
|
|
16
|
-
from email.
|
|
16
|
+
from email.mime.multipart import MIMEMultipart
|
|
17
|
+
from email.mime.text import MIMEText
|
|
17
18
|
|
|
18
19
|
import aiosmtplib
|
|
19
20
|
|
|
@@ -69,8 +70,19 @@ class MailNotification(base.NotificationBase):
|
|
|
69
70
|
alert: typing.Optional[mlrun.common.schemas.AlertConfig] = None,
|
|
70
71
|
event_data: typing.Optional[mlrun.common.schemas.Event] = None,
|
|
71
72
|
):
|
|
72
|
-
self.params
|
|
73
|
-
self.params.
|
|
73
|
+
self.params["subject"] = f"[{severity}] {message}"
|
|
74
|
+
message_body_override = self.params.get("message_body_override", None)
|
|
75
|
+
|
|
76
|
+
runs_html = self._get_html(
|
|
77
|
+
message, severity, runs, custom_html, alert, event_data
|
|
78
|
+
)
|
|
79
|
+
self.params["body"] = runs_html
|
|
80
|
+
|
|
81
|
+
if message_body_override:
|
|
82
|
+
self.params["body"] = message_body_override.replace(
|
|
83
|
+
"{{ runs }}", runs_html
|
|
84
|
+
).replace("{{runs}}", runs_html)
|
|
85
|
+
|
|
74
86
|
await self._send_email(**self.params)
|
|
75
87
|
|
|
76
88
|
@classmethod
|
|
@@ -84,13 +96,28 @@ class MailNotification(base.NotificationBase):
|
|
|
84
96
|
params.setdefault("server_port", DEFAULT_SMTP_PORT)
|
|
85
97
|
|
|
86
98
|
default_mail_address = params.pop("default_email_addresses", "")
|
|
87
|
-
email_addresses =
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
params["email_addresses"] = email_addresses
|
|
99
|
+
params["email_addresses"] = cls._merge_mail_addresses(
|
|
100
|
+
default_mail_address, params.get("email_addresses", "")
|
|
101
|
+
)
|
|
91
102
|
|
|
92
103
|
return params
|
|
93
104
|
|
|
105
|
+
@classmethod
|
|
106
|
+
def _merge_mail_addresses(
|
|
107
|
+
cls,
|
|
108
|
+
default_mail_address: typing.Union[str, list],
|
|
109
|
+
email_addresses: typing.Union[str, list],
|
|
110
|
+
) -> str:
|
|
111
|
+
if isinstance(default_mail_address, str):
|
|
112
|
+
default_mail_address = (
|
|
113
|
+
default_mail_address.split(",") if default_mail_address else []
|
|
114
|
+
)
|
|
115
|
+
if isinstance(email_addresses, str):
|
|
116
|
+
email_addresses = email_addresses.split(",") if email_addresses else []
|
|
117
|
+
email_addresses.extend(default_mail_address)
|
|
118
|
+
email_addresses_str = ",".join(email_addresses)
|
|
119
|
+
return email_addresses_str
|
|
120
|
+
|
|
94
121
|
@classmethod
|
|
95
122
|
def _validate_emails(cls, params):
|
|
96
123
|
cls._validate_email_address(params["sender_address"])
|
|
@@ -130,11 +157,11 @@ class MailNotification(base.NotificationBase):
|
|
|
130
157
|
**kwargs,
|
|
131
158
|
):
|
|
132
159
|
# Create the email message
|
|
133
|
-
message =
|
|
160
|
+
message = MIMEMultipart("alternative")
|
|
134
161
|
message["From"] = sender_address
|
|
135
162
|
message["To"] = email_addresses
|
|
136
163
|
message["Subject"] = subject
|
|
137
|
-
message.
|
|
164
|
+
message.attach(MIMEText(body, "html"))
|
|
138
165
|
|
|
139
166
|
# Send the email
|
|
140
167
|
await aiosmtplib.send(
|
|
@@ -21,7 +21,7 @@ import typing
|
|
|
21
21
|
from concurrent.futures import ThreadPoolExecutor
|
|
22
22
|
|
|
23
23
|
import mlrun.common.constants as mlrun_constants
|
|
24
|
-
import mlrun.common.runtimes.constants
|
|
24
|
+
import mlrun.common.runtimes.constants as runtimes_constants
|
|
25
25
|
import mlrun.common.schemas
|
|
26
26
|
import mlrun.config
|
|
27
27
|
import mlrun.db.base
|
|
@@ -118,21 +118,37 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
118
118
|
] = []
|
|
119
119
|
|
|
120
120
|
for run in self._runs:
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
try:
|
|
122
|
+
self._process_run(run)
|
|
123
|
+
except Exception as exc:
|
|
124
|
+
logger.warning(
|
|
125
|
+
"Failed to process run",
|
|
126
|
+
run_uid=run.metadata.uid,
|
|
127
|
+
error=mlrun.errors.err_to_str(exc),
|
|
128
|
+
)
|
|
123
129
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
notification.name
|
|
128
|
-
).get("status", mlrun.common.schemas.NotificationStatus.PENDING)
|
|
129
|
-
except (AttributeError, KeyError):
|
|
130
|
-
notification.status = (
|
|
131
|
-
mlrun.common.schemas.NotificationStatus.PENDING
|
|
132
|
-
)
|
|
130
|
+
def _process_run(self, run):
|
|
131
|
+
if isinstance(run, dict):
|
|
132
|
+
run = mlrun.model.RunObject.from_dict(run)
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
for notification in run.spec.notifications:
|
|
135
|
+
try:
|
|
136
|
+
self._process_notification(notification, run)
|
|
137
|
+
except Exception as exc:
|
|
138
|
+
logger.warning(
|
|
139
|
+
"Failed to process notification",
|
|
140
|
+
run_uid=run.metadata.uid,
|
|
141
|
+
notification=notification,
|
|
142
|
+
error=mlrun.errors.err_to_str(exc),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def _process_notification(self, notification, run):
|
|
146
|
+
notification.status = run.status.notifications.get(notification.name, {}).get(
|
|
147
|
+
"status",
|
|
148
|
+
mlrun.common.schemas.NotificationStatus.PENDING,
|
|
149
|
+
)
|
|
150
|
+
if self._should_notify(run, notification):
|
|
151
|
+
self._load_notification(run, notification)
|
|
136
152
|
|
|
137
153
|
def push(self):
|
|
138
154
|
"""
|
|
@@ -176,6 +192,11 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
176
192
|
logger.warning(
|
|
177
193
|
"Failed to push notification async",
|
|
178
194
|
error=mlrun.errors.err_to_str(result),
|
|
195
|
+
traceback=traceback.format_exception(
|
|
196
|
+
etype=type(result),
|
|
197
|
+
value=result,
|
|
198
|
+
tb=result.__traceback__,
|
|
199
|
+
),
|
|
179
200
|
)
|
|
180
201
|
|
|
181
202
|
logger.debug(
|
|
@@ -205,7 +226,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
205
226
|
for when_state in when_states:
|
|
206
227
|
if when_state == run_state:
|
|
207
228
|
if (
|
|
208
|
-
run_state ==
|
|
229
|
+
run_state == runtimes_constants.RunStates.completed
|
|
209
230
|
and evaluate_condition_in_separate_process(
|
|
210
231
|
notification.condition,
|
|
211
232
|
context={
|
|
@@ -213,7 +234,11 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
213
234
|
"notification": notification.to_dict(),
|
|
214
235
|
},
|
|
215
236
|
)
|
|
216
|
-
) or run_state in [
|
|
237
|
+
) or run_state in [
|
|
238
|
+
runtimes_constants.RunStates.error,
|
|
239
|
+
runtimes_constants.RunStates.aborted,
|
|
240
|
+
runtimes_constants.RunStates.running,
|
|
241
|
+
]:
|
|
217
242
|
return True
|
|
218
243
|
|
|
219
244
|
return False
|
|
@@ -420,7 +445,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
420
445
|
_run["step_kind"] = _step.step_type
|
|
421
446
|
if _step.skipped:
|
|
422
447
|
_run.setdefault("status", {})["state"] = (
|
|
423
|
-
|
|
448
|
+
runtimes_constants.RunStates.skipped
|
|
424
449
|
)
|
|
425
450
|
steps.append(_run)
|
|
426
451
|
|
|
@@ -447,7 +472,7 @@ class NotificationPusher(_NotificationPusherBase):
|
|
|
447
472
|
if _step.skipped:
|
|
448
473
|
state = mlrun.common.schemas.FunctionState.skipped
|
|
449
474
|
else:
|
|
450
|
-
state =
|
|
475
|
+
state = runtimes_constants.PodPhases.pod_phase_to_run_state(
|
|
451
476
|
pod_phase
|
|
452
477
|
)
|
|
453
478
|
function["status"] = {"state": state}
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.0rc7
|
|
4
4
|
Summary: Tracking and config of machine learning runs
|
|
5
5
|
Home-page: https://github.com/mlrun/mlrun
|
|
6
6
|
Author: Yaron Haviv
|
|
@@ -32,13 +32,14 @@ Requires-Dist: nuclio-jupyter~=0.11.1
|
|
|
32
32
|
Requires-Dist: numpy<1.27.0,>=1.26.4
|
|
33
33
|
Requires-Dist: pandas<2.2,>=1.2
|
|
34
34
|
Requires-Dist: pyarrow<18,>=10.0
|
|
35
|
-
Requires-Dist: pyyaml<7,>=
|
|
35
|
+
Requires-Dist: pyyaml<7,>=6.0.2
|
|
36
36
|
Requires-Dist: requests~=2.32
|
|
37
37
|
Requires-Dist: tabulate~=0.8.6
|
|
38
38
|
Requires-Dist: v3io~=0.6.9
|
|
39
39
|
Requires-Dist: pydantic>=1.10.15
|
|
40
40
|
Requires-Dist: mergedeep~=1.3
|
|
41
|
-
Requires-Dist: v3io-frames~=0.10.14
|
|
41
|
+
Requires-Dist: v3io-frames~=0.10.14; python_version < "3.11"
|
|
42
|
+
Requires-Dist: v3io-frames!=0.11.*,!=0.12.*,>=0.10.14; python_version >= "3.11"
|
|
42
43
|
Requires-Dist: semver~=3.0
|
|
43
44
|
Requires-Dist: dependency-injector~=4.41
|
|
44
45
|
Requires-Dist: fsspec<2024.7,>=2023.9.2
|
|
@@ -51,7 +52,7 @@ Requires-Dist: deprecated~=1.2
|
|
|
51
52
|
Requires-Dist: jinja2>=3.1.3,~=3.1
|
|
52
53
|
Requires-Dist: orjson<4,>=3.9.15
|
|
53
54
|
Requires-Dist: mlrun-pipelines-kfp-common~=0.2.3
|
|
54
|
-
Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.
|
|
55
|
+
Requires-Dist: mlrun-pipelines-kfp-v1-8~=0.2.3; python_version < "3.11"
|
|
55
56
|
Requires-Dist: docstring_parser~=0.16
|
|
56
57
|
Requires-Dist: aiosmtplib~=3.0
|
|
57
58
|
Provides-Extra: s3
|