mlrun 1.8.0rc38__py3-none-any.whl → 1.8.0rc40__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/__main__.py +1 -8
- mlrun/artifacts/base.py +3 -3
- mlrun/artifacts/manager.py +1 -1
- mlrun/common/schemas/client_spec.py +1 -0
- mlrun/common/schemas/model_monitoring/constants.py +2 -4
- mlrun/common/schemas/model_monitoring/model_endpoints.py +5 -11
- mlrun/config.py +5 -4
- mlrun/datastore/base.py +0 -11
- mlrun/db/httpdb.py +11 -0
- mlrun/feature_store/api.py +3 -0
- mlrun/model_monitoring/api.py +2 -20
- mlrun/model_monitoring/controller.py +19 -3
- mlrun/model_monitoring/db/tsdb/base.py +11 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +13 -9
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +83 -7
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +38 -4
- mlrun/projects/operations.py +3 -3
- mlrun/projects/pipelines.py +5 -0
- mlrun/projects/project.py +4 -4
- mlrun/run.py +4 -4
- mlrun/runtimes/kubejob.py +2 -2
- mlrun/runtimes/nuclio/application/application.py +0 -2
- mlrun/runtimes/nuclio/function.py +1 -46
- mlrun/runtimes/nuclio/serving.py +1 -1
- mlrun/runtimes/pod.py +37 -145
- mlrun/serving/routers.py +80 -64
- mlrun/serving/v2_serving.py +24 -62
- mlrun/utils/async_http.py +1 -2
- mlrun/utils/helpers.py +1 -2
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/METADATA +4 -4
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/RECORD +36 -36
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/WHEEL +1 -1
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc38.dist-info → mlrun-1.8.0rc40.dist-info}/top_level.txt +0 -0
mlrun/__main__.py
CHANGED
|
@@ -17,7 +17,6 @@ import json
|
|
|
17
17
|
import pathlib
|
|
18
18
|
import socket
|
|
19
19
|
import traceback
|
|
20
|
-
import warnings
|
|
21
20
|
from ast import literal_eval
|
|
22
21
|
from base64 import b64decode
|
|
23
22
|
from os import environ, path, remove
|
|
@@ -864,14 +863,8 @@ def version():
|
|
|
864
863
|
)
|
|
865
864
|
@click.option("--offset", type=int, default=0, help="byte offset")
|
|
866
865
|
@click.option("--db", help="api and db service path/url")
|
|
867
|
-
|
|
868
|
-
def logs(uid, project, offset, db, watch):
|
|
866
|
+
def logs(uid, project, offset, db):
|
|
869
867
|
"""Get or watch task logs"""
|
|
870
|
-
if watch:
|
|
871
|
-
warnings.warn(
|
|
872
|
-
"'--watch' is deprecated in 1.6.0, and will be removed in 1.8.0, "
|
|
873
|
-
# TODO: Remove in 1.8.0
|
|
874
|
-
)
|
|
875
868
|
mldb = get_run_db(db or mlconf.dbpath)
|
|
876
869
|
if mldb.kind == "http":
|
|
877
870
|
state, _ = mldb.watch_log(uid, project, watch=False, offset=offset)
|
mlrun/artifacts/base.py
CHANGED
|
@@ -893,7 +893,7 @@ def generate_target_path(item: Artifact, artifact_path, producer):
|
|
|
893
893
|
return f"{artifact_path}{item.key}{suffix}"
|
|
894
894
|
|
|
895
895
|
|
|
896
|
-
# TODO:
|
|
896
|
+
# TODO: Remove once data migration v5 is obsolete
|
|
897
897
|
def convert_legacy_artifact_to_new_format(
|
|
898
898
|
legacy_artifact: dict,
|
|
899
899
|
) -> Artifact:
|
|
@@ -905,9 +905,9 @@ def convert_legacy_artifact_to_new_format(
|
|
|
905
905
|
artifact_tag = legacy_artifact.get("tag", "")
|
|
906
906
|
if artifact_tag:
|
|
907
907
|
artifact_key = f"{artifact_key}:{artifact_tag}"
|
|
908
|
-
# TODO:
|
|
908
|
+
# TODO: Remove once data migration v5 is obsolete
|
|
909
909
|
warnings.warn(
|
|
910
|
-
f"Converting legacy artifact '{artifact_key}' to new format. This will not be supported in MLRun 1.
|
|
910
|
+
f"Converting legacy artifact '{artifact_key}' to new format. This will not be supported in MLRun 1.9.0. "
|
|
911
911
|
f"Make sure to save the artifact/project in the new format.",
|
|
912
912
|
FutureWarning,
|
|
913
913
|
)
|
mlrun/artifacts/manager.py
CHANGED
|
@@ -108,7 +108,7 @@ class ArtifactProducer:
|
|
|
108
108
|
def dict_to_artifact(struct: dict) -> Artifact:
|
|
109
109
|
kind = struct.get("kind", "")
|
|
110
110
|
|
|
111
|
-
# TODO:
|
|
111
|
+
# TODO: Remove once data migration v5 is obsolete
|
|
112
112
|
if mlrun.utils.is_legacy_artifact(struct):
|
|
113
113
|
return mlrun.artifacts.base.convert_legacy_artifact_to_new_format(struct)
|
|
114
114
|
|
|
@@ -42,12 +42,10 @@ class ModelEndpointSchema(MonitoringStrEnum):
|
|
|
42
42
|
# spec
|
|
43
43
|
FUNCTION_NAME = "function_name"
|
|
44
44
|
FUNCTION_TAG = "function_tag"
|
|
45
|
-
FUNCTION_UID = "function_uid"
|
|
46
45
|
MODEL_NAME = "model_name"
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
MODEL_TAGS = "model_tags"
|
|
47
|
+
MODEL_PATH = "model_path"
|
|
49
48
|
MODEL_CLASS = "model_class"
|
|
50
|
-
MODEL_UID = "model_uid"
|
|
51
49
|
FEATURE_NAMES = "feature_names"
|
|
52
50
|
LABEL_NAMES = "label_names"
|
|
53
51
|
FEATURE_STATS = "feature_stats"
|
|
@@ -117,14 +117,13 @@ class ModelEndpointMetadata(ObjectMetadata, ModelEndpointParser):
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
class ModelEndpointSpec(ObjectSpec, ModelEndpointParser):
|
|
120
|
-
model_uid: Optional[str] = ""
|
|
121
|
-
model_name: Optional[str] = ""
|
|
122
|
-
model_db_key: Optional[str] = ""
|
|
123
|
-
model_tag: Optional[str] = ""
|
|
124
120
|
model_class: Optional[str] = ""
|
|
125
121
|
function_name: Optional[str] = ""
|
|
126
122
|
function_tag: Optional[str] = ""
|
|
127
|
-
|
|
123
|
+
model_path: Optional[str] = ""
|
|
124
|
+
model_name: Optional[str] = ""
|
|
125
|
+
model_tags: Optional[list[str]] = []
|
|
126
|
+
_model_id: Optional[int] = ""
|
|
128
127
|
feature_names: Optional[list[str]] = []
|
|
129
128
|
label_names: Optional[list[str]] = []
|
|
130
129
|
feature_stats: Optional[dict] = {}
|
|
@@ -137,12 +136,8 @@ class ModelEndpointSpec(ObjectSpec, ModelEndpointParser):
|
|
|
137
136
|
@classmethod
|
|
138
137
|
def mutable_fields(cls):
|
|
139
138
|
return [
|
|
140
|
-
"
|
|
141
|
-
"model_name",
|
|
142
|
-
"model_db_key",
|
|
143
|
-
"model_tag",
|
|
139
|
+
"model_path",
|
|
144
140
|
"model_class",
|
|
145
|
-
"function_uid",
|
|
146
141
|
"feature_names",
|
|
147
142
|
"label_names",
|
|
148
143
|
"children",
|
|
@@ -206,7 +201,6 @@ class ModelEndpoint(BaseModel):
|
|
|
206
201
|
ModelEndpointSchema.CURRENT_STATS,
|
|
207
202
|
ModelEndpointSchema.DRIFT_MEASURES,
|
|
208
203
|
ModelEndpointSchema.FUNCTION_URI,
|
|
209
|
-
ModelEndpointSchema.MODEL_URI,
|
|
210
204
|
}
|
|
211
205
|
# Initialize a flattened dictionary that will be filled with the model endpoint dictionary attributes
|
|
212
206
|
flatten_dict = {}
|
mlrun/config.py
CHANGED
|
@@ -232,6 +232,7 @@ default_config = {
|
|
|
232
232
|
"delete_project": "900",
|
|
233
233
|
"delete_function": "900",
|
|
234
234
|
"model_endpoint_creation": "600",
|
|
235
|
+
"model_endpoint_tsdb_leftovers": "900",
|
|
235
236
|
},
|
|
236
237
|
"runtimes": {"dask": "600"},
|
|
237
238
|
"push_notifications": "60",
|
|
@@ -566,16 +567,16 @@ default_config = {
|
|
|
566
567
|
},
|
|
567
568
|
"application_stream_args": {
|
|
568
569
|
"v3io": {
|
|
569
|
-
"shard_count":
|
|
570
|
+
"shard_count": 4,
|
|
570
571
|
"retention_period_hours": 24,
|
|
571
|
-
"num_workers":
|
|
572
|
+
"num_workers": 4,
|
|
572
573
|
"min_replicas": 1,
|
|
573
574
|
"max_replicas": 1,
|
|
574
575
|
},
|
|
575
576
|
"kafka": {
|
|
576
|
-
"partition_count":
|
|
577
|
+
"partition_count": 4,
|
|
577
578
|
"replication_factor": 1,
|
|
578
|
-
"num_workers":
|
|
579
|
+
"num_workers": 4,
|
|
579
580
|
"min_replicas": 1,
|
|
580
581
|
"max_replicas": 1,
|
|
581
582
|
},
|
mlrun/datastore/base.py
CHANGED
|
@@ -24,7 +24,6 @@ import pandas as pd
|
|
|
24
24
|
import pyarrow
|
|
25
25
|
import pytz
|
|
26
26
|
import requests
|
|
27
|
-
from deprecated import deprecated
|
|
28
27
|
|
|
29
28
|
import mlrun.config
|
|
30
29
|
import mlrun.errors
|
|
@@ -95,16 +94,6 @@ class DataStore:
|
|
|
95
94
|
def uri_to_ipython(endpoint, subpath):
|
|
96
95
|
return ""
|
|
97
96
|
|
|
98
|
-
# TODO: remove in 1.8.0
|
|
99
|
-
@deprecated(
|
|
100
|
-
version="1.8.0",
|
|
101
|
-
reason="'get_filesystem()' will be removed in 1.8.0, use "
|
|
102
|
-
"'filesystem' property instead",
|
|
103
|
-
category=FutureWarning,
|
|
104
|
-
)
|
|
105
|
-
def get_filesystem(self):
|
|
106
|
-
return self.filesystem
|
|
107
|
-
|
|
108
97
|
@property
|
|
109
98
|
def filesystem(self) -> Optional[fsspec.AbstractFileSystem]:
|
|
110
99
|
"""return fsspec file system object, if supported"""
|
mlrun/db/httpdb.py
CHANGED
|
@@ -566,6 +566,17 @@ class HTTPRunDB(RunDBInterface):
|
|
|
566
566
|
)
|
|
567
567
|
config.alerts.mode = server_cfg.get("alerts_mode") or config.alerts.mode
|
|
568
568
|
config.system_id = server_cfg.get("system_id") or config.system_id
|
|
569
|
+
model_monitoring_store_prefixes = (
|
|
570
|
+
server_cfg.get("model_endpoint_monitoring_store_prefixes") or {}
|
|
571
|
+
)
|
|
572
|
+
for prefix in ["default", "user_space", "monitoring_application"]:
|
|
573
|
+
store_prefix_value = model_monitoring_store_prefixes.get(prefix)
|
|
574
|
+
if server_prefix_value is not None:
|
|
575
|
+
setattr(
|
|
576
|
+
config.model_endpoint_monitoring.store_prefixes,
|
|
577
|
+
prefix,
|
|
578
|
+
store_prefix_value,
|
|
579
|
+
)
|
|
569
580
|
|
|
570
581
|
except Exception as exc:
|
|
571
582
|
logger.warning(
|
mlrun/feature_store/api.py
CHANGED
|
@@ -708,6 +708,9 @@ def _deploy_ingestion_service_v2(
|
|
|
708
708
|
function.metadata.name = function.metadata.name or name
|
|
709
709
|
|
|
710
710
|
function.spec.graph = featureset.spec.graph
|
|
711
|
+
function.spec.graph.engine = (
|
|
712
|
+
"async" if featureset.spec.engine == "storey" else "sync"
|
|
713
|
+
)
|
|
711
714
|
function.spec.parameters = run_config.parameters
|
|
712
715
|
function.spec.graph_initializer = (
|
|
713
716
|
"mlrun.feature_store.ingestion.featureset_initializer"
|
mlrun/model_monitoring/api.py
CHANGED
|
@@ -118,8 +118,6 @@ def get_or_create_model_endpoint(
|
|
|
118
118
|
model_endpoint_name=model_endpoint_name,
|
|
119
119
|
function_name=function_name,
|
|
120
120
|
function_tag=function_tag,
|
|
121
|
-
context=context,
|
|
122
|
-
sample_set_statistics=sample_set_statistics,
|
|
123
121
|
monitoring_mode=monitoring_mode,
|
|
124
122
|
)
|
|
125
123
|
return model_endpoint
|
|
@@ -344,8 +342,6 @@ def _generate_model_endpoint(
|
|
|
344
342
|
model_endpoint_name: str,
|
|
345
343
|
function_name: str,
|
|
346
344
|
function_tag: str,
|
|
347
|
-
context: "mlrun.MLClientCtx",
|
|
348
|
-
sample_set_statistics: dict[str, typing.Any],
|
|
349
345
|
monitoring_mode: mm_constants.ModelMonitoringMode = mm_constants.ModelMonitoringMode.enabled,
|
|
350
346
|
) -> ModelEndpoint:
|
|
351
347
|
"""
|
|
@@ -358,21 +354,10 @@ def _generate_model_endpoint(
|
|
|
358
354
|
:param model_endpoint_name: Model endpoint name will be presented under the new model endpoint.
|
|
359
355
|
:param function_name: If a new model endpoint is created, use this function name.
|
|
360
356
|
:param function_tag: If a new model endpoint is created, use this function tag.
|
|
361
|
-
:param
|
|
362
|
-
full function hash.
|
|
363
|
-
:param sample_set_statistics: Dictionary of sample set statistics that will be used as a reference data for
|
|
364
|
-
the current model endpoint. Will be stored under
|
|
365
|
-
`model_endpoint.status.feature_stats`.
|
|
357
|
+
:param monitoring_mode: Monitoring mode of the new model endpoint.
|
|
366
358
|
|
|
367
359
|
:return `mlrun.common.schemas.ModelEndpoint` object.
|
|
368
360
|
"""
|
|
369
|
-
model_obj = None
|
|
370
|
-
if model_path:
|
|
371
|
-
model_obj: mlrun.artifacts.ModelArtifact = (
|
|
372
|
-
mlrun.datastore.store_resources.get_store_resource(
|
|
373
|
-
model_path, db=db_session
|
|
374
|
-
)
|
|
375
|
-
)
|
|
376
361
|
current_time = datetime_now()
|
|
377
362
|
model_endpoint = mlrun.common.schemas.ModelEndpoint(
|
|
378
363
|
metadata=mlrun.common.schemas.ModelEndpointMetadata(
|
|
@@ -383,10 +368,7 @@ def _generate_model_endpoint(
|
|
|
383
368
|
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
384
369
|
function_name=function_name or "function",
|
|
385
370
|
function_tag=function_tag or "latest",
|
|
386
|
-
|
|
387
|
-
model_uid=model_obj.metadata.uid if model_obj else None,
|
|
388
|
-
model_tag=model_obj.metadata.tag if model_obj else None,
|
|
389
|
-
model_db_key=model_obj.spec.db_key if model_obj else None,
|
|
371
|
+
model_path=model_path,
|
|
390
372
|
model_class="drift-analysis",
|
|
391
373
|
),
|
|
392
374
|
status=mlrun.common.schemas.ModelEndpointStatus(
|
|
@@ -16,6 +16,7 @@ import concurrent.futures
|
|
|
16
16
|
import datetime
|
|
17
17
|
import json
|
|
18
18
|
import os
|
|
19
|
+
import traceback
|
|
19
20
|
from collections.abc import Iterator
|
|
20
21
|
from contextlib import AbstractContextManager
|
|
21
22
|
from types import TracebackType
|
|
@@ -499,7 +500,7 @@ class MonitoringApplicationController:
|
|
|
499
500
|
app_name=app_name,
|
|
500
501
|
app_stream_type=str(type(app_stream)),
|
|
501
502
|
)
|
|
502
|
-
app_stream.push([data])
|
|
503
|
+
app_stream.push([data], partition_key=endpoint_id)
|
|
503
504
|
|
|
504
505
|
def push_regular_event_to_controller_stream(self) -> None:
|
|
505
506
|
"""
|
|
@@ -551,14 +552,29 @@ class MonitoringApplicationController:
|
|
|
551
552
|
with concurrent.futures.ThreadPoolExecutor(
|
|
552
553
|
max_workers=min(len(endpoints), 10)
|
|
553
554
|
) as pool:
|
|
554
|
-
|
|
555
|
+
futures = {
|
|
555
556
|
pool.submit(
|
|
556
557
|
MonitoringApplicationController.endpoint_to_regular_event,
|
|
557
558
|
endpoint,
|
|
558
559
|
policy,
|
|
559
560
|
set(applications_names),
|
|
560
561
|
self.v3io_access_key,
|
|
561
|
-
)
|
|
562
|
+
): endpoint
|
|
563
|
+
for endpoint in endpoints
|
|
564
|
+
}
|
|
565
|
+
for future in concurrent.futures.as_completed(futures):
|
|
566
|
+
if future.exception():
|
|
567
|
+
exception = future.exception()
|
|
568
|
+
error = (
|
|
569
|
+
f"Failed to push event. Endpoint name: {futures[future].metadata.name}, "
|
|
570
|
+
f"endpoint uid: {futures[future].metadata.uid}, traceback:\n"
|
|
571
|
+
)
|
|
572
|
+
error += "".join(
|
|
573
|
+
traceback.format_exception(
|
|
574
|
+
None, exception, exception.__traceback__
|
|
575
|
+
)
|
|
576
|
+
)
|
|
577
|
+
logger.error(error)
|
|
562
578
|
logger.info("Finishing monitoring controller chief")
|
|
563
579
|
|
|
564
580
|
@staticmethod
|
|
@@ -80,6 +80,17 @@ class TSDBConnector(ABC):
|
|
|
80
80
|
:raise mlrun.errors.MLRunRuntimeError: If an error occurred while writing the event.
|
|
81
81
|
"""
|
|
82
82
|
|
|
83
|
+
@abstractmethod
|
|
84
|
+
def delete_tsdb_records(
|
|
85
|
+
self, endpoint_ids: list[str], delete_timeout: Optional[int] = None
|
|
86
|
+
) -> None:
|
|
87
|
+
"""
|
|
88
|
+
Delete model endpoint records from the TSDB connector.
|
|
89
|
+
:param endpoint_ids: List of model endpoint unique identifiers.
|
|
90
|
+
:param delete_timeout: The timeout in seconds to wait for the deletion to complete.
|
|
91
|
+
"""
|
|
92
|
+
pass
|
|
93
|
+
|
|
83
94
|
@abstractmethod
|
|
84
95
|
def delete_tsdb_resources(self):
|
|
85
96
|
"""
|
|
@@ -122,26 +122,30 @@ class TDEngineSchema:
|
|
|
122
122
|
)
|
|
123
123
|
return f"DELETE FROM {self.database}.{subtable} WHERE {values};"
|
|
124
124
|
|
|
125
|
-
def
|
|
125
|
+
def drop_subtable_query(
|
|
126
126
|
self,
|
|
127
127
|
subtable: str,
|
|
128
128
|
) -> str:
|
|
129
|
-
return f"DROP TABLE if EXISTS {self.database}
|
|
129
|
+
return f"DROP TABLE if EXISTS {self.database}.`{subtable}`;"
|
|
130
130
|
|
|
131
131
|
def drop_supertable_query(self) -> str:
|
|
132
132
|
return f"DROP STABLE if EXISTS {self.database}.{self.super_table};"
|
|
133
133
|
|
|
134
|
-
def
|
|
134
|
+
def _get_subtables_query_by_tag(
|
|
135
135
|
self,
|
|
136
|
-
|
|
136
|
+
filter_tag: str,
|
|
137
|
+
filter_values: list[str],
|
|
138
|
+
operator: str = "OR",
|
|
137
139
|
) -> str:
|
|
138
|
-
|
|
139
|
-
f"{val} LIKE '{values[val]}'" for val in self.tags if val in values
|
|
140
|
-
)
|
|
141
|
-
if not values:
|
|
140
|
+
if filter_tag not in self.tags:
|
|
142
141
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
143
|
-
f"
|
|
142
|
+
f"`filter_tag` must be one of the tags: {self.tags.keys()}"
|
|
144
143
|
)
|
|
144
|
+
|
|
145
|
+
values = f" {operator} ".join(
|
|
146
|
+
f"{filter_tag} LIKE '{val}'" for val in filter_values
|
|
147
|
+
)
|
|
148
|
+
|
|
145
149
|
return f"SELECT DISTINCT tbname FROM {self.database}.{self.super_table} WHERE {values};"
|
|
146
150
|
|
|
147
151
|
@staticmethod
|
|
@@ -75,13 +75,8 @@ class TDEngineConnector(TSDBConnector):
|
|
|
75
75
|
"""Establish a connection to the TSDB server."""
|
|
76
76
|
logger.debug("Creating a new connection to TDEngine", project=self.project)
|
|
77
77
|
conn = TDEngineConnection(self._tdengine_connection_profile.dsn())
|
|
78
|
-
conn.run(
|
|
79
|
-
statements=f"CREATE DATABASE IF NOT EXISTS {self.database}",
|
|
80
|
-
timeout=self._timeout,
|
|
81
|
-
retries=self._retries,
|
|
82
|
-
)
|
|
83
78
|
conn.prefix_statements = [f"USE {self.database}"]
|
|
84
|
-
|
|
79
|
+
|
|
85
80
|
return conn
|
|
86
81
|
|
|
87
82
|
def _init_super_tables(self):
|
|
@@ -101,8 +96,27 @@ class TDEngineConnector(TSDBConnector):
|
|
|
101
96
|
),
|
|
102
97
|
}
|
|
103
98
|
|
|
99
|
+
def _create_db_if_not_exists(self):
|
|
100
|
+
"""Create the database if it does not exist."""
|
|
101
|
+
self.connection.prefix_statements = []
|
|
102
|
+
self.connection.run(
|
|
103
|
+
statements=f"CREATE DATABASE IF NOT EXISTS {self.database}",
|
|
104
|
+
timeout=self._timeout,
|
|
105
|
+
retries=self._retries,
|
|
106
|
+
)
|
|
107
|
+
self.connection.prefix_statements = [f"USE {self.database}"]
|
|
108
|
+
logger.debug(
|
|
109
|
+
"The TDEngine database is currently in use",
|
|
110
|
+
project=self.project,
|
|
111
|
+
database=self.database,
|
|
112
|
+
)
|
|
113
|
+
|
|
104
114
|
def create_tables(self):
|
|
105
115
|
"""Create TDEngine supertables."""
|
|
116
|
+
|
|
117
|
+
# Create the database if it does not exist
|
|
118
|
+
self._create_db_if_not_exists()
|
|
119
|
+
|
|
106
120
|
for table in self.tables:
|
|
107
121
|
create_table_query = self.tables[table]._create_super_table_query()
|
|
108
122
|
conn = self.connection
|
|
@@ -272,6 +286,67 @@ class TDEngineConnector(TSDBConnector):
|
|
|
272
286
|
flush_after_seconds=tsdb_batching_timeout_secs,
|
|
273
287
|
)
|
|
274
288
|
|
|
289
|
+
def delete_tsdb_records(
|
|
290
|
+
self, endpoint_ids: list[str], delete_timeout: Optional[int] = None
|
|
291
|
+
):
|
|
292
|
+
"""
|
|
293
|
+
To delete subtables within TDEngine, we first query the subtables names with the provided endpoint_ids.
|
|
294
|
+
Then, we drop each subtable.
|
|
295
|
+
"""
|
|
296
|
+
logger.debug(
|
|
297
|
+
"Deleting model endpoint resources using the TDEngine connector",
|
|
298
|
+
project=self.project,
|
|
299
|
+
number_of_endpoints_to_delete=len(endpoint_ids),
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
# Get all subtables with the provided endpoint_ids
|
|
303
|
+
subtables = []
|
|
304
|
+
try:
|
|
305
|
+
for table in self.tables:
|
|
306
|
+
get_subtable_query = self.tables[table]._get_subtables_query_by_tag(
|
|
307
|
+
filter_tag="endpoint_id", filter_values=endpoint_ids
|
|
308
|
+
)
|
|
309
|
+
subtables_result = self.connection.run(
|
|
310
|
+
query=get_subtable_query,
|
|
311
|
+
timeout=self._timeout,
|
|
312
|
+
retries=self._retries,
|
|
313
|
+
)
|
|
314
|
+
subtables.extend([subtable[0] for subtable in subtables_result.data])
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.warning(
|
|
317
|
+
"Failed to get subtables for deletion. You may need to delete them manually."
|
|
318
|
+
"These can be found under the following supertables: app_results, "
|
|
319
|
+
"metrics, errors, and predictions.",
|
|
320
|
+
project=self.project,
|
|
321
|
+
error=mlrun.errors.err_to_str(e),
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
# Prepare the drop statements
|
|
325
|
+
drop_statements = []
|
|
326
|
+
for subtable in subtables:
|
|
327
|
+
drop_statements.append(
|
|
328
|
+
self.tables[table].drop_subtable_query(subtable=subtable)
|
|
329
|
+
)
|
|
330
|
+
try:
|
|
331
|
+
self.connection.run(
|
|
332
|
+
statements=drop_statements,
|
|
333
|
+
timeout=delete_timeout or self._timeout,
|
|
334
|
+
retries=self._retries,
|
|
335
|
+
)
|
|
336
|
+
except Exception as e:
|
|
337
|
+
logger.warning(
|
|
338
|
+
"Failed to delete model endpoint resources. You may need to delete them manually. "
|
|
339
|
+
"These can be found under the following supertables: app_results, "
|
|
340
|
+
"metrics, errors, and predictions.",
|
|
341
|
+
project=self.project,
|
|
342
|
+
error=mlrun.errors.err_to_str(e),
|
|
343
|
+
)
|
|
344
|
+
logger.debug(
|
|
345
|
+
"Deleted all model endpoint resources using the TDEngine connector",
|
|
346
|
+
project=self.project,
|
|
347
|
+
number_of_endpoints_to_delete=len(endpoint_ids),
|
|
348
|
+
)
|
|
349
|
+
|
|
275
350
|
def delete_tsdb_resources(self):
|
|
276
351
|
"""
|
|
277
352
|
Delete all project resources in the TSDB connector, such as model endpoints data and drift results.
|
|
@@ -294,7 +369,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
294
369
|
logger.warning(
|
|
295
370
|
"Failed to drop TDEngine tables. You may need to drop them manually. "
|
|
296
371
|
"These can be found under the following supertables: app_results, "
|
|
297
|
-
"metrics, and predictions.",
|
|
372
|
+
"metrics, errors, and predictions.",
|
|
298
373
|
project=self.project,
|
|
299
374
|
error=mlrun.errors.err_to_str(e),
|
|
300
375
|
)
|
|
@@ -344,6 +419,7 @@ class TDEngineConnector(TSDBConnector):
|
|
|
344
419
|
project=self.project,
|
|
345
420
|
database=self.database,
|
|
346
421
|
)
|
|
422
|
+
|
|
347
423
|
except Exception as e:
|
|
348
424
|
logger.warning(
|
|
349
425
|
"Failed to drop the database. You may need to drop it manually if it is empty.",
|
|
@@ -428,6 +428,40 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
428
428
|
store, _, _ = mlrun.store_manager.get_or_create_store(tsdb_path)
|
|
429
429
|
store.rm(tsdb_path, recursive=True)
|
|
430
430
|
|
|
431
|
+
def delete_tsdb_records(
|
|
432
|
+
self, endpoint_ids: list[str], delete_timeout: Optional[int] = None
|
|
433
|
+
):
|
|
434
|
+
logger.debug(
|
|
435
|
+
"Deleting model endpoints resources using the V3IO TSDB connector",
|
|
436
|
+
project=self.project,
|
|
437
|
+
number_of_endpoints_to_delete=len(endpoint_ids),
|
|
438
|
+
)
|
|
439
|
+
tables = mm_schemas.V3IOTSDBTables.list()
|
|
440
|
+
|
|
441
|
+
# Split the endpoint ids into chunks to avoid exceeding the v3io-engine filter-expression limit
|
|
442
|
+
for i in range(0, len(endpoint_ids), V3IO_MEPS_LIMIT):
|
|
443
|
+
endpoint_id_chunk = endpoint_ids[i : i + V3IO_MEPS_LIMIT]
|
|
444
|
+
filter_query = f"endpoint_id IN({str(endpoint_id_chunk)[1:-1]}) "
|
|
445
|
+
for table in tables:
|
|
446
|
+
try:
|
|
447
|
+
self.frames_client.delete(
|
|
448
|
+
backend=_TSDB_BE,
|
|
449
|
+
table=self.tables[table],
|
|
450
|
+
filter=filter_query,
|
|
451
|
+
start="0",
|
|
452
|
+
)
|
|
453
|
+
except Exception as e:
|
|
454
|
+
logger.warning(
|
|
455
|
+
f"Failed to delete TSDB records for the provided endpoints from table '{table}'",
|
|
456
|
+
error=mlrun.errors.err_to_str(e),
|
|
457
|
+
project=self.project,
|
|
458
|
+
)
|
|
459
|
+
logger.debug(
|
|
460
|
+
"Deleted all model endpoint resources using the V3IO connector",
|
|
461
|
+
project=self.project,
|
|
462
|
+
number_of_endpoints_to_delete=len(endpoint_ids),
|
|
463
|
+
)
|
|
464
|
+
|
|
431
465
|
def get_model_endpoint_real_time_metrics(
|
|
432
466
|
self, endpoint_id: str, metrics: list[str], start: str, end: str
|
|
433
467
|
) -> dict[str, list[tuple[str, float]]]:
|
|
@@ -1052,12 +1086,12 @@ class V3IOTSDBConnector(TSDBConnector):
|
|
|
1052
1086
|
)
|
|
1053
1087
|
add_metric(
|
|
1054
1088
|
"avg_latency",
|
|
1055
|
-
"
|
|
1056
|
-
|
|
1089
|
+
"avg(latency)",
|
|
1090
|
+
avg_latency_res,
|
|
1057
1091
|
)
|
|
1058
1092
|
add_metric(
|
|
1059
1093
|
"result_status",
|
|
1060
|
-
"
|
|
1061
|
-
|
|
1094
|
+
"max(result_status)",
|
|
1095
|
+
drift_status_res,
|
|
1062
1096
|
)
|
|
1063
1097
|
return list(model_endpoint_objects_by_uid.values())
|
mlrun/projects/operations.py
CHANGED
|
@@ -294,9 +294,9 @@ def build_function(
|
|
|
294
294
|
:param force_build: Force building the image, even when no changes were made
|
|
295
295
|
"""
|
|
296
296
|
if not overwrite_build_params:
|
|
297
|
-
# TODO: change overwrite_build_params default to True in 1.
|
|
297
|
+
# TODO: change overwrite_build_params default to True in 1.9.0
|
|
298
298
|
warnings.warn(
|
|
299
|
-
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.
|
|
299
|
+
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.9.0.",
|
|
300
300
|
mlrun.utils.OverwriteBuildParamsWarning,
|
|
301
301
|
)
|
|
302
302
|
|
|
@@ -325,7 +325,7 @@ def build_function(
|
|
|
325
325
|
skip_deployed=skip_deployed,
|
|
326
326
|
)
|
|
327
327
|
else:
|
|
328
|
-
# TODO: remove filter once overwrite_build_params default is changed to True in 1.
|
|
328
|
+
# TODO: remove filter once overwrite_build_params default is changed to True in 1.9.0
|
|
329
329
|
with warnings.catch_warnings():
|
|
330
330
|
warnings.simplefilter(
|
|
331
331
|
"ignore", category=mlrun.utils.OverwriteBuildParamsWarning
|
mlrun/projects/pipelines.py
CHANGED
|
@@ -1139,6 +1139,11 @@ def load_and_run_workflow(
|
|
|
1139
1139
|
if "running" in notification.when
|
|
1140
1140
|
]
|
|
1141
1141
|
|
|
1142
|
+
# Prevent redundant notifications for run completion by ensuring that notifications are only triggered when the run
|
|
1143
|
+
# reaches the "running" state, as the server already handles the completion notifications.
|
|
1144
|
+
for notification in start_notifications:
|
|
1145
|
+
notification.when = ["running"]
|
|
1146
|
+
|
|
1142
1147
|
workflow_log_message = workflow_name or workflow_path
|
|
1143
1148
|
context.logger.info(f"Running workflow {workflow_log_message} from remote")
|
|
1144
1149
|
run = project.run(
|
mlrun/projects/project.py
CHANGED
|
@@ -4059,9 +4059,9 @@ class MlrunProject(ModelObj):
|
|
|
4059
4059
|
(by default `/home/mlrun_code`)
|
|
4060
4060
|
"""
|
|
4061
4061
|
if not overwrite_build_params:
|
|
4062
|
-
# TODO: change overwrite_build_params default to True in 1.
|
|
4062
|
+
# TODO: change overwrite_build_params default to True in 1.9.0
|
|
4063
4063
|
warnings.warn(
|
|
4064
|
-
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.
|
|
4064
|
+
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.9.0.",
|
|
4065
4065
|
mlrun.utils.OverwriteBuildParamsWarning,
|
|
4066
4066
|
)
|
|
4067
4067
|
default_image_name = mlrun.mlconf.default_project_image_name.format(
|
|
@@ -4136,9 +4136,9 @@ class MlrunProject(ModelObj):
|
|
|
4136
4136
|
)
|
|
4137
4137
|
|
|
4138
4138
|
if not overwrite_build_params:
|
|
4139
|
-
# TODO: change overwrite_build_params default to True in 1.
|
|
4139
|
+
# TODO: change overwrite_build_params default to True in 1.9.0
|
|
4140
4140
|
warnings.warn(
|
|
4141
|
-
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.
|
|
4141
|
+
"The `overwrite_build_params` parameter default will change from 'False' to 'True' in 1.9.0.",
|
|
4142
4142
|
mlrun.utils.OverwriteBuildParamsWarning,
|
|
4143
4143
|
)
|
|
4144
4144
|
|
mlrun/run.py
CHANGED
|
@@ -36,9 +36,9 @@ import mlrun.common.formatters
|
|
|
36
36
|
import mlrun.common.schemas
|
|
37
37
|
import mlrun.errors
|
|
38
38
|
import mlrun.utils.helpers
|
|
39
|
+
import mlrun_pipelines.utils
|
|
39
40
|
from mlrun_pipelines.common.models import RunStatuses
|
|
40
41
|
from mlrun_pipelines.common.ops import format_summary_from_kfp_run, show_kfp_run
|
|
41
|
-
from mlrun_pipelines.utils import get_client
|
|
42
42
|
|
|
43
43
|
from .common.helpers import parse_versioned_object_uri
|
|
44
44
|
from .config import config as mlconf
|
|
@@ -437,7 +437,7 @@ def new_function(
|
|
|
437
437
|
mode: Optional[str] = None,
|
|
438
438
|
handler: Optional[str] = None,
|
|
439
439
|
source: Optional[str] = None,
|
|
440
|
-
requirements: Optional[
|
|
440
|
+
requirements: Optional[list[str]] = None,
|
|
441
441
|
kfp: Optional[bool] = None,
|
|
442
442
|
requirements_file: str = "",
|
|
443
443
|
):
|
|
@@ -1015,7 +1015,7 @@ def wait_for_pipeline_completion(
|
|
|
1015
1015
|
_wait_for_pipeline_completion,
|
|
1016
1016
|
)
|
|
1017
1017
|
else:
|
|
1018
|
-
client = get_client(namespace=namespace)
|
|
1018
|
+
client = mlrun_pipelines.utils.get_client(namespace=namespace)
|
|
1019
1019
|
resp = client.wait_for_run_completion(run_id, timeout)
|
|
1020
1020
|
if resp:
|
|
1021
1021
|
resp = resp.to_dict()
|
|
@@ -1076,7 +1076,7 @@ def get_pipeline(
|
|
|
1076
1076
|
)
|
|
1077
1077
|
|
|
1078
1078
|
else:
|
|
1079
|
-
client = get_client(namespace=namespace)
|
|
1079
|
+
client = mlrun_pipelines.utils.get_client(namespace=namespace)
|
|
1080
1080
|
resp = client.get_run(run_id)
|
|
1081
1081
|
if resp:
|
|
1082
1082
|
resp = resp.to_dict()
|
mlrun/runtimes/kubejob.py
CHANGED
|
@@ -114,9 +114,9 @@ class KubejobRuntime(KubeResource):
|
|
|
114
114
|
e.g. builder_env={"GIT_TOKEN": token}
|
|
115
115
|
"""
|
|
116
116
|
if not overwrite:
|
|
117
|
-
# TODO: change overwrite default to True in 1.
|
|
117
|
+
# TODO: change overwrite default to True in 1.9.0
|
|
118
118
|
warnings.warn(
|
|
119
|
-
"The `overwrite` parameter default will change from 'False' to 'True' in 1.
|
|
119
|
+
"The `overwrite` parameter default will change from 'False' to 'True' in 1.9.0.",
|
|
120
120
|
mlrun.utils.OverwriteBuildParamsWarning,
|
|
121
121
|
)
|
|
122
122
|
image = mlrun.utils.helpers.remove_image_protocol_prefix(image)
|