mlrun 1.7.0rc58__py3-none-any.whl → 1.7.1rc1__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/config.py +54 -3
- mlrun/datastore/__init__.py +2 -2
- mlrun/features.py +2 -1
- mlrun/model_monitoring/applications/_application_steps.py +12 -10
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +1 -1
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +27 -6
- mlrun/platforms/iguazio.py +30 -10
- mlrun/serving/v2_serving.py +59 -23
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/METADATA +2 -2
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/RECORD +15 -15
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/WHEEL +1 -1
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/LICENSE +0 -0
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/entry_points.txt +0 -0
- {mlrun-1.7.0rc58.dist-info → mlrun-1.7.1rc1.dist-info}/top_level.txt +0 -0
mlrun/config.py
CHANGED
|
@@ -49,6 +49,7 @@ _load_lock = Lock()
|
|
|
49
49
|
_none_type = type(None)
|
|
50
50
|
default_env_file = os.getenv("MLRUN_DEFAULT_ENV_FILE", "~/.mlrun.env")
|
|
51
51
|
|
|
52
|
+
|
|
52
53
|
default_config = {
|
|
53
54
|
"namespace": "", # default kubernetes namespace
|
|
54
55
|
"kubernetes": {
|
|
@@ -532,8 +533,55 @@ default_config = {
|
|
|
532
533
|
},
|
|
533
534
|
},
|
|
534
535
|
"model_endpoint_monitoring": {
|
|
535
|
-
"
|
|
536
|
-
|
|
536
|
+
"serving_stream": {
|
|
537
|
+
"v3io": {
|
|
538
|
+
"shard_count": 2,
|
|
539
|
+
"retention_period_hours": 24,
|
|
540
|
+
"num_workers": 1,
|
|
541
|
+
"min_replicas": 2,
|
|
542
|
+
"max_replicas": 2,
|
|
543
|
+
},
|
|
544
|
+
"kafka": {
|
|
545
|
+
"partition_count": 8,
|
|
546
|
+
"replication_factor": 1,
|
|
547
|
+
"num_workers": 2,
|
|
548
|
+
"min_replicas": 1,
|
|
549
|
+
"max_replicas": 4,
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
"application_stream_args": {
|
|
553
|
+
"v3io": {
|
|
554
|
+
"shard_count": 1,
|
|
555
|
+
"retention_period_hours": 24,
|
|
556
|
+
"num_workers": 1,
|
|
557
|
+
"min_replicas": 1,
|
|
558
|
+
"max_replicas": 1,
|
|
559
|
+
},
|
|
560
|
+
"kafka": {
|
|
561
|
+
"partition_count": 1,
|
|
562
|
+
"replication_factor": 1,
|
|
563
|
+
"num_workers": 1,
|
|
564
|
+
"min_replicas": 1,
|
|
565
|
+
"max_replicas": 1,
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
"writer_stream_args": {
|
|
569
|
+
"v3io": {
|
|
570
|
+
"shard_count": 1,
|
|
571
|
+
"retention_period_hours": 24,
|
|
572
|
+
"num_workers": 1,
|
|
573
|
+
"min_replicas": 1,
|
|
574
|
+
"max_replicas": 1,
|
|
575
|
+
},
|
|
576
|
+
"kafka": {
|
|
577
|
+
"partition_count": 1,
|
|
578
|
+
# TODO: add retention period configuration
|
|
579
|
+
"replication_factor": 1,
|
|
580
|
+
"num_workers": 1,
|
|
581
|
+
"min_replicas": 1,
|
|
582
|
+
"max_replicas": 1,
|
|
583
|
+
},
|
|
584
|
+
},
|
|
537
585
|
# Store prefixes are used to handle model monitoring storing policies based on project and kind, such as events,
|
|
538
586
|
# stream, and endpoints.
|
|
539
587
|
"store_prefixes": {
|
|
@@ -556,6 +604,10 @@ default_config = {
|
|
|
556
604
|
"tsdb_connection": "",
|
|
557
605
|
# See mlrun.common.schemas.model_monitoring.constants.StreamKind for available options
|
|
558
606
|
"stream_connection": "",
|
|
607
|
+
"tdengine": {
|
|
608
|
+
"timeout": 10,
|
|
609
|
+
"retries": 1,
|
|
610
|
+
},
|
|
559
611
|
},
|
|
560
612
|
"secret_stores": {
|
|
561
613
|
# Use only in testing scenarios (such as integration tests) to avoid using k8s for secrets (will use in-memory
|
|
@@ -746,7 +798,6 @@ default_config = {
|
|
|
746
798
|
"request_timeout": 5,
|
|
747
799
|
},
|
|
748
800
|
}
|
|
749
|
-
|
|
750
801
|
_is_running_as_api = None
|
|
751
802
|
|
|
752
803
|
|
mlrun/datastore/__init__.py
CHANGED
|
@@ -131,9 +131,9 @@ class _DummyStream:
|
|
|
131
131
|
def __init__(self, event_list=None, **kwargs):
|
|
132
132
|
self.event_list = event_list or []
|
|
133
133
|
|
|
134
|
-
def push(self, data):
|
|
134
|
+
def push(self, data, **kwargs):
|
|
135
135
|
if not isinstance(data, list):
|
|
136
136
|
data = [data]
|
|
137
137
|
for item in data:
|
|
138
|
-
logger.info(f"dummy stream got event: {item}")
|
|
138
|
+
logger.info(f"dummy stream got event: {item}, kwargs={kwargs}")
|
|
139
139
|
self.event_list.append(item)
|
mlrun/features.py
CHANGED
|
@@ -100,7 +100,8 @@ class Feature(ModelObj):
|
|
|
100
100
|
:param name: name of the feature
|
|
101
101
|
:param validator: feature validation policy
|
|
102
102
|
:param default: default value
|
|
103
|
-
:param labels: a set of key/value labels (tags)
|
|
103
|
+
:param labels: a set of key/value labels (tags). Labels can be used to filter featues, for example,
|
|
104
|
+
in the UI Feature store page.
|
|
104
105
|
"""
|
|
105
106
|
self.name = name or ""
|
|
106
107
|
if isinstance(value_type, ValueType):
|
|
@@ -162,10 +162,17 @@ class _ApplicationErrorHandler(StepToDict):
|
|
|
162
162
|
:param event: Application event.
|
|
163
163
|
"""
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
error_data = {
|
|
166
|
+
"Endpoint ID": event.body.endpoint_id,
|
|
167
|
+
"Application Class": event.body.application_name,
|
|
168
|
+
"Error": "".join(
|
|
169
|
+
traceback.format_exception(None, event.error, event.error.__traceback__)
|
|
170
|
+
),
|
|
171
|
+
"Timestamp": event.timestamp,
|
|
172
|
+
}
|
|
173
|
+
logger.error("Error in application step", **error_data)
|
|
174
|
+
|
|
175
|
+
error_data["Error"] = event.error
|
|
169
176
|
|
|
170
177
|
event_data = alert_objects.Event(
|
|
171
178
|
kind=alert_objects.EventKind.MM_APP_FAILED,
|
|
@@ -174,12 +181,7 @@ class _ApplicationErrorHandler(StepToDict):
|
|
|
174
181
|
project=self.project,
|
|
175
182
|
ids=[f"{self.project}_{event.body.application_name}"],
|
|
176
183
|
),
|
|
177
|
-
value_dict=
|
|
178
|
-
"Error": event.error,
|
|
179
|
-
"Timestamp": event.timestamp,
|
|
180
|
-
"Application Class": event.body.application_name,
|
|
181
|
-
"Endpoint ID": event.body.endpoint_id,
|
|
182
|
-
},
|
|
184
|
+
value_dict=error_data,
|
|
183
185
|
)
|
|
184
186
|
|
|
185
187
|
mlrun.get_run_db().generate_event(
|
|
@@ -159,7 +159,7 @@ class TDEngineSchema:
|
|
|
159
159
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
160
160
|
f"values must contain at least one tag: {self.tags.keys()}"
|
|
161
161
|
)
|
|
162
|
-
return f"SELECT tbname FROM {self.database}.{self.super_table} WHERE {values};"
|
|
162
|
+
return f"SELECT DISTINCT tbname FROM {self.database}.{self.super_table} WHERE {values};"
|
|
163
163
|
|
|
164
164
|
@staticmethod
|
|
165
165
|
def _get_records_query(
|
|
@@ -56,6 +56,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
56
56
|
self._connection = None
|
|
57
57
|
self._init_super_tables()
|
|
58
58
|
|
|
59
|
+
self._timeout = mlrun.mlconf.model_endpoint_monitoring.tdengine.timeout
|
|
60
|
+
self._retries = mlrun.mlconf.model_endpoint_monitoring.tdengine.retries
|
|
61
|
+
|
|
59
62
|
@property
|
|
60
63
|
def connection(self) -> TDEngineConnection:
|
|
61
64
|
if not self._connection:
|
|
@@ -66,7 +69,11 @@ class TDEngineConnector(TSDBConnector):
|
|
|
66
69
|
"""Establish a connection to the TSDB server."""
|
|
67
70
|
logger.debug("Creating a new connection to TDEngine", project=self.project)
|
|
68
71
|
conn = TDEngineConnection(self._tdengine_connection_string)
|
|
69
|
-
conn.run(
|
|
72
|
+
conn.run(
|
|
73
|
+
statements=f"CREATE DATABASE IF NOT EXISTS {self.database}",
|
|
74
|
+
timeout=self._timeout,
|
|
75
|
+
retries=self._retries,
|
|
76
|
+
)
|
|
70
77
|
conn.prefix_statements = [f"USE {self.database}"]
|
|
71
78
|
logger.debug("Connected to TDEngine", project=self.project)
|
|
72
79
|
return conn
|
|
@@ -89,7 +96,11 @@ class TDEngineConnector(TSDBConnector):
|
|
|
89
96
|
"""Create TDEngine supertables."""
|
|
90
97
|
for table in self.tables:
|
|
91
98
|
create_table_query = self.tables[table]._create_super_table_query()
|
|
92
|
-
self.connection.run(
|
|
99
|
+
self.connection.run(
|
|
100
|
+
statements=create_table_query,
|
|
101
|
+
timeout=self._timeout,
|
|
102
|
+
retries=self._retries,
|
|
103
|
+
)
|
|
93
104
|
|
|
94
105
|
def write_application_event(
|
|
95
106
|
self,
|
|
@@ -145,7 +156,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
145
156
|
statements=[
|
|
146
157
|
create_table_sql,
|
|
147
158
|
insert_statement,
|
|
148
|
-
]
|
|
159
|
+
],
|
|
160
|
+
timeout=self._timeout,
|
|
161
|
+
retries=self._retries,
|
|
149
162
|
)
|
|
150
163
|
|
|
151
164
|
@staticmethod
|
|
@@ -211,13 +224,19 @@ class TDEngineConnector(TSDBConnector):
|
|
|
211
224
|
get_subtable_names_query = self.tables[table]._get_subtables_query(
|
|
212
225
|
values={mm_schemas.EventFieldType.PROJECT: self.project}
|
|
213
226
|
)
|
|
214
|
-
subtables = self.connection.run(
|
|
227
|
+
subtables = self.connection.run(
|
|
228
|
+
query=get_subtable_names_query,
|
|
229
|
+
timeout=self._timeout,
|
|
230
|
+
retries=self._retries,
|
|
231
|
+
).data
|
|
215
232
|
drop_statements = []
|
|
216
233
|
for subtable in subtables:
|
|
217
234
|
drop_statements.append(
|
|
218
235
|
self.tables[table]._drop_subtable_query(subtable=subtable[0])
|
|
219
236
|
)
|
|
220
|
-
self.connection.run(
|
|
237
|
+
self.connection.run(
|
|
238
|
+
statements=drop_statements, timeout=self._timeout, retries=self._retries
|
|
239
|
+
)
|
|
221
240
|
logger.debug(
|
|
222
241
|
"Deleted all project resources using the TDEngine connector",
|
|
223
242
|
project=self.project,
|
|
@@ -291,7 +310,9 @@ class TDEngineConnector(TSDBConnector):
|
|
|
291
310
|
)
|
|
292
311
|
logger.debug("Querying TDEngine", query=full_query)
|
|
293
312
|
try:
|
|
294
|
-
query_result = self.connection.run(
|
|
313
|
+
query_result = self.connection.run(
|
|
314
|
+
query=full_query, timeout=self._timeout, retries=self._retries
|
|
315
|
+
)
|
|
295
316
|
except taosws.QueryError as e:
|
|
296
317
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
297
318
|
f"Failed to query table {table} in database {self.database}, {str(e)}"
|
mlrun/platforms/iguazio.py
CHANGED
|
@@ -97,26 +97,33 @@ class OutputStream:
|
|
|
97
97
|
|
|
98
98
|
self._v3io_client = v3io.dataplane.Client(**v3io_client_kwargs)
|
|
99
99
|
self._container, self._stream_path = split_path(stream_path)
|
|
100
|
+
self._shards = shards
|
|
101
|
+
self._retention_in_hours = retention_in_hours
|
|
102
|
+
self._create = create
|
|
103
|
+
self._endpoint = endpoint
|
|
100
104
|
self._mock = mock
|
|
101
105
|
self._mock_queue = []
|
|
102
106
|
|
|
103
|
-
|
|
107
|
+
def _lazy_init(self):
|
|
108
|
+
if self._create and not self._mock:
|
|
104
109
|
# this import creates an import loop via the utils module, so putting it in execution path
|
|
105
110
|
from mlrun.utils.helpers import logger
|
|
106
111
|
|
|
112
|
+
self._create = False
|
|
113
|
+
|
|
107
114
|
logger.debug(
|
|
108
115
|
"Creating output stream",
|
|
109
|
-
endpoint=
|
|
116
|
+
endpoint=self._endpoint,
|
|
110
117
|
container=self._container,
|
|
111
118
|
stream_path=self._stream_path,
|
|
112
|
-
shards=
|
|
113
|
-
retention_in_hours=
|
|
119
|
+
shards=self._shards,
|
|
120
|
+
retention_in_hours=self._retention_in_hours,
|
|
114
121
|
)
|
|
115
122
|
response = self._v3io_client.stream.create(
|
|
116
123
|
container=self._container,
|
|
117
124
|
stream_path=self._stream_path,
|
|
118
|
-
shard_count=
|
|
119
|
-
retention_period_hours=
|
|
125
|
+
shard_count=self._shards or 1,
|
|
126
|
+
retention_period_hours=self._retention_in_hours or 24,
|
|
120
127
|
raise_for_status=v3io.dataplane.RaiseForStatus.never,
|
|
121
128
|
)
|
|
122
129
|
if not (
|
|
@@ -124,7 +131,9 @@ class OutputStream:
|
|
|
124
131
|
):
|
|
125
132
|
response.raise_for_status([409, 204])
|
|
126
133
|
|
|
127
|
-
def push(self, data):
|
|
134
|
+
def push(self, data, partition_key=None):
|
|
135
|
+
self._lazy_init()
|
|
136
|
+
|
|
128
137
|
def dump_record(rec):
|
|
129
138
|
if not isinstance(rec, (str, bytes)):
|
|
130
139
|
return dict_to_json(rec)
|
|
@@ -132,7 +141,14 @@ class OutputStream:
|
|
|
132
141
|
|
|
133
142
|
if not isinstance(data, list):
|
|
134
143
|
data = [data]
|
|
135
|
-
|
|
144
|
+
|
|
145
|
+
records = []
|
|
146
|
+
for rec in data:
|
|
147
|
+
record = {"data": dump_record(rec)}
|
|
148
|
+
if partition_key is not None:
|
|
149
|
+
record["partition_key"] = partition_key
|
|
150
|
+
records.append(record)
|
|
151
|
+
|
|
136
152
|
if self._mock:
|
|
137
153
|
# for mock testing
|
|
138
154
|
self._mock_queue.extend(records)
|
|
@@ -205,7 +221,7 @@ class KafkaOutputStream:
|
|
|
205
221
|
|
|
206
222
|
self._initialized = True
|
|
207
223
|
|
|
208
|
-
def push(self, data):
|
|
224
|
+
def push(self, data, partition_key=None):
|
|
209
225
|
self._lazy_init()
|
|
210
226
|
|
|
211
227
|
def dump_record(rec):
|
|
@@ -226,7 +242,11 @@ class KafkaOutputStream:
|
|
|
226
242
|
else:
|
|
227
243
|
for record in data:
|
|
228
244
|
serialized_record = dump_record(record)
|
|
229
|
-
|
|
245
|
+
if isinstance(partition_key, str):
|
|
246
|
+
partition_key = partition_key.encode("UTF-8")
|
|
247
|
+
self._kafka_producer.send(
|
|
248
|
+
self._topic, serialized_record, key=partition_key
|
|
249
|
+
)
|
|
230
250
|
|
|
231
251
|
|
|
232
252
|
class V3ioStreamClient:
|
mlrun/serving/v2_serving.py
CHANGED
|
@@ -39,6 +39,7 @@ class V2ModelServer(StepToDict):
|
|
|
39
39
|
protocol=None,
|
|
40
40
|
input_path: str = None,
|
|
41
41
|
result_path: str = None,
|
|
42
|
+
shard_by_endpoint: Optional[bool] = None,
|
|
42
43
|
**kwargs,
|
|
43
44
|
):
|
|
44
45
|
"""base model serving class (v2), using similar API to KFServing v2 and Triton
|
|
@@ -91,6 +92,8 @@ class V2ModelServer(StepToDict):
|
|
|
91
92
|
this require that the event body will behave like a dict, example:
|
|
92
93
|
event: {"x": 5} , result_path="resp" means the returned response will be written
|
|
93
94
|
to event["y"] resulting in {"x": 5, "resp": <result>}
|
|
95
|
+
:param shard_by_endpoint: whether to use the endpoint as the partition/sharding key when writing to model
|
|
96
|
+
monitoring stream. Defaults to True.
|
|
94
97
|
:param kwargs: extra arguments (can be accessed using self.get_param(key))
|
|
95
98
|
"""
|
|
96
99
|
self.name = name
|
|
@@ -119,7 +122,9 @@ class V2ModelServer(StepToDict):
|
|
|
119
122
|
if model:
|
|
120
123
|
self.model = model
|
|
121
124
|
self.ready = True
|
|
125
|
+
self._versioned_model_name = None
|
|
122
126
|
self.model_endpoint_uid = None
|
|
127
|
+
self.shard_by_endpoint = shard_by_endpoint
|
|
123
128
|
|
|
124
129
|
def _load_and_update_state(self):
|
|
125
130
|
try:
|
|
@@ -225,6 +230,23 @@ class V2ModelServer(StepToDict):
|
|
|
225
230
|
request = self.preprocess(event_body, op)
|
|
226
231
|
return self.validate(request, op)
|
|
227
232
|
|
|
233
|
+
@property
|
|
234
|
+
def versioned_model_name(self):
|
|
235
|
+
if self._versioned_model_name:
|
|
236
|
+
return self._versioned_model_name
|
|
237
|
+
|
|
238
|
+
# Generating version model value based on the model name and model version
|
|
239
|
+
if self.model_path and self.model_path.startswith("store://"):
|
|
240
|
+
# Enrich the model server with the model artifact metadata
|
|
241
|
+
self.get_model()
|
|
242
|
+
if not self.version:
|
|
243
|
+
# Enrich the model version with the model artifact tag
|
|
244
|
+
self.version = self.model_spec.tag
|
|
245
|
+
self.labels = self.model_spec.labels
|
|
246
|
+
version = self.version or "latest"
|
|
247
|
+
self._versioned_model_name = f"{self.name}:{version}"
|
|
248
|
+
return self._versioned_model_name
|
|
249
|
+
|
|
228
250
|
def do_event(self, event, *args, **kwargs):
|
|
229
251
|
"""main model event handler method"""
|
|
230
252
|
start = now_date()
|
|
@@ -232,6 +254,11 @@ class V2ModelServer(StepToDict):
|
|
|
232
254
|
event_body = _extract_input_data(self._input_path, event.body)
|
|
233
255
|
event_id = event.id
|
|
234
256
|
op = event.path.strip("/")
|
|
257
|
+
|
|
258
|
+
partition_key = (
|
|
259
|
+
self.model_endpoint_uid if self.shard_by_endpoint is not False else None
|
|
260
|
+
)
|
|
261
|
+
|
|
235
262
|
if event_body and isinstance(event_body, dict):
|
|
236
263
|
op = op or event_body.get("operation")
|
|
237
264
|
event_id = event_body.get("id", event_id)
|
|
@@ -251,7 +278,13 @@ class V2ModelServer(StepToDict):
|
|
|
251
278
|
except Exception as exc:
|
|
252
279
|
request["id"] = event_id
|
|
253
280
|
if self._model_logger:
|
|
254
|
-
self._model_logger.push(
|
|
281
|
+
self._model_logger.push(
|
|
282
|
+
start,
|
|
283
|
+
request,
|
|
284
|
+
op=op,
|
|
285
|
+
error=exc,
|
|
286
|
+
partition_key=partition_key,
|
|
287
|
+
)
|
|
255
288
|
raise exc
|
|
256
289
|
|
|
257
290
|
response = {
|
|
@@ -288,7 +321,7 @@ class V2ModelServer(StepToDict):
|
|
|
288
321
|
setattr(event, "terminated", True)
|
|
289
322
|
event_body = {
|
|
290
323
|
"name": self.name,
|
|
291
|
-
"version": self.version,
|
|
324
|
+
"version": self.version or "",
|
|
292
325
|
"inputs": [],
|
|
293
326
|
"outputs": [],
|
|
294
327
|
}
|
|
@@ -308,7 +341,13 @@ class V2ModelServer(StepToDict):
|
|
|
308
341
|
except Exception as exc:
|
|
309
342
|
request["id"] = event_id
|
|
310
343
|
if self._model_logger:
|
|
311
|
-
self._model_logger.push(
|
|
344
|
+
self._model_logger.push(
|
|
345
|
+
start,
|
|
346
|
+
request,
|
|
347
|
+
op=op,
|
|
348
|
+
error=exc,
|
|
349
|
+
partition_key=partition_key,
|
|
350
|
+
)
|
|
312
351
|
raise exc
|
|
313
352
|
|
|
314
353
|
response = {
|
|
@@ -332,12 +371,20 @@ class V2ModelServer(StepToDict):
|
|
|
332
371
|
if self._model_logger:
|
|
333
372
|
inputs, outputs = self.logged_results(request, response, op)
|
|
334
373
|
if inputs is None and outputs is None:
|
|
335
|
-
self._model_logger.push(
|
|
374
|
+
self._model_logger.push(
|
|
375
|
+
start, request, response, op, partition_key=partition_key
|
|
376
|
+
)
|
|
336
377
|
else:
|
|
337
378
|
track_request = {"id": event_id, "inputs": inputs or []}
|
|
338
379
|
track_response = {"outputs": outputs or []}
|
|
339
380
|
# TODO : check dict/list
|
|
340
|
-
self._model_logger.push(
|
|
381
|
+
self._model_logger.push(
|
|
382
|
+
start,
|
|
383
|
+
track_request,
|
|
384
|
+
track_response,
|
|
385
|
+
op,
|
|
386
|
+
partition_key=partition_key,
|
|
387
|
+
)
|
|
341
388
|
event.body = _update_result_body(self._result_path, original_body, response)
|
|
342
389
|
return event
|
|
343
390
|
|
|
@@ -454,7 +501,7 @@ class _ModelLogPusher:
|
|
|
454
501
|
base_data["labels"] = self.model.labels
|
|
455
502
|
return base_data
|
|
456
503
|
|
|
457
|
-
def push(self, start, request, resp=None, op=None, error=None):
|
|
504
|
+
def push(self, start, request, resp=None, op=None, error=None, partition_key=None):
|
|
458
505
|
start_str = start.isoformat(sep=" ", timespec="microseconds")
|
|
459
506
|
if error:
|
|
460
507
|
data = self.base_data()
|
|
@@ -465,7 +512,7 @@ class _ModelLogPusher:
|
|
|
465
512
|
if self.verbose:
|
|
466
513
|
message = f"{message}\n{traceback.format_exc()}"
|
|
467
514
|
data["error"] = message
|
|
468
|
-
self.output_stream.push([data])
|
|
515
|
+
self.output_stream.push([data], partition_key=partition_key)
|
|
469
516
|
return
|
|
470
517
|
|
|
471
518
|
self._sample_iter = (self._sample_iter + 1) % self.stream_sample
|
|
@@ -491,7 +538,7 @@ class _ModelLogPusher:
|
|
|
491
538
|
"metrics",
|
|
492
539
|
]
|
|
493
540
|
data["values"] = self._batch
|
|
494
|
-
self.output_stream.push([data])
|
|
541
|
+
self.output_stream.push([data], partition_key=partition_key)
|
|
495
542
|
else:
|
|
496
543
|
data = self.base_data()
|
|
497
544
|
data["request"] = request
|
|
@@ -501,7 +548,7 @@ class _ModelLogPusher:
|
|
|
501
548
|
data["microsec"] = microsec
|
|
502
549
|
if getattr(self.model, "metrics", None):
|
|
503
550
|
data["metrics"] = self.model.metrics
|
|
504
|
-
self.output_stream.push([data])
|
|
551
|
+
self.output_stream.push([data], partition_key=partition_key)
|
|
505
552
|
|
|
506
553
|
|
|
507
554
|
def _init_endpoint_record(
|
|
@@ -531,21 +578,10 @@ def _init_endpoint_record(
|
|
|
531
578
|
logger.error("Failed to parse function URI", exc=err_to_str(e))
|
|
532
579
|
return None
|
|
533
580
|
|
|
534
|
-
# Generating version model value based on the model name and model version
|
|
535
|
-
if model.model_path and model.model_path.startswith("store://"):
|
|
536
|
-
# Enrich the model server with the model artifact metadata
|
|
537
|
-
model.get_model()
|
|
538
|
-
if not model.version:
|
|
539
|
-
# Enrich the model version with the model artifact tag
|
|
540
|
-
model.version = model.model_spec.tag
|
|
541
|
-
model.labels = model.model_spec.labels
|
|
542
|
-
versioned_model_name = f"{model.name}:{model.version}"
|
|
543
|
-
else:
|
|
544
|
-
versioned_model_name = f"{model.name}:latest"
|
|
545
|
-
|
|
546
581
|
# Generating model endpoint ID based on function uri and model version
|
|
547
582
|
uid = mlrun.common.model_monitoring.create_model_endpoint_uid(
|
|
548
|
-
function_uri=graph_server.function_uri,
|
|
583
|
+
function_uri=graph_server.function_uri,
|
|
584
|
+
versioned_model=model.versioned_model_name,
|
|
549
585
|
).uid
|
|
550
586
|
|
|
551
587
|
try:
|
|
@@ -568,7 +604,7 @@ def _init_endpoint_record(
|
|
|
568
604
|
),
|
|
569
605
|
spec=mlrun.common.schemas.ModelEndpointSpec(
|
|
570
606
|
function_uri=graph_server.function_uri,
|
|
571
|
-
model=versioned_model_name,
|
|
607
|
+
model=model.versioned_model_name,
|
|
572
608
|
model_class=model.__class__.__name__,
|
|
573
609
|
model_uri=model.model_path,
|
|
574
610
|
stream_path=model.context.stream.stream_uri,
|
mlrun/utils/version/version.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mlrun
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.1rc1
|
|
4
4
|
Summary: Tracking and config of machine learning runs
|
|
5
5
|
Home-page: https://github.com/mlrun/mlrun
|
|
6
6
|
Author: Yaron Haviv
|
|
@@ -43,7 +43,7 @@ Requires-Dist: semver ~=3.0
|
|
|
43
43
|
Requires-Dist: dependency-injector ~=4.41
|
|
44
44
|
Requires-Dist: fsspec <2024.7,>=2023.9.2
|
|
45
45
|
Requires-Dist: v3iofs ~=0.1.17
|
|
46
|
-
Requires-Dist: storey
|
|
46
|
+
Requires-Dist: storey ~=1.7.50
|
|
47
47
|
Requires-Dist: inflection ~=0.5.0
|
|
48
48
|
Requires-Dist: python-dotenv ~=0.17.0
|
|
49
49
|
Requires-Dist: setuptools ~=71.0
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
mlrun/__init__.py,sha256=y08M1JcKXy5-9_5WaI9fn5aV5BxIQ5QkbduJK0OxWbA,7470
|
|
2
2
|
mlrun/__main__.py,sha256=mC_Izs4kuHUHQi88QJFLN22n1kbygGM0wAirjNt7uj4,45938
|
|
3
|
-
mlrun/config.py,sha256=
|
|
3
|
+
mlrun/config.py,sha256=DbVVAW1kgjtW0Bkm5bymE2_Wxd-0iHV_hoAlRDnQZDA,68743
|
|
4
4
|
mlrun/errors.py,sha256=G8GP4_wb3v2UEbiAS8OlamC7nYJNzbSvQ3sViZlyYhk,8063
|
|
5
5
|
mlrun/execution.py,sha256=nXvvN8euzjuxhJouJD8VxfK0keTTA6UoMrcD_17AL-4,44252
|
|
6
|
-
mlrun/features.py,sha256=
|
|
6
|
+
mlrun/features.py,sha256=1VlN5mdSvUrLSJJlJWk4mXp9YoNxkFTu36IGn9AbN7s,15539
|
|
7
7
|
mlrun/k8s_utils.py,sha256=mRQMs6NzPq36vx1n5_2BfFapXysc8wv3NcrZ77_2ANA,8949
|
|
8
8
|
mlrun/lists.py,sha256=3PqBdcajdwhTe1XuFsAaHTuFVM2kjwepf31qqE82apg,8384
|
|
9
9
|
mlrun/model.py,sha256=S6CKiRrYfgVNALA9TLy4lsXZCox4FpD-TAnR5CU51cQ,82035
|
|
@@ -77,7 +77,7 @@ mlrun/data_types/data_types.py,sha256=uB9qJusSvPRK2PTvrFBXrS5jcDXMuwqXokJGToDg4V
|
|
|
77
77
|
mlrun/data_types/infer.py,sha256=z2EbSpR6xWEE5-HRUtDZkapHQld3xMbzXtTX83K-690,6134
|
|
78
78
|
mlrun/data_types/spark.py,sha256=xfcr6lcaLcHepnrHavx_vacMJK7BC8FWsUKjwrjjn6w,9509
|
|
79
79
|
mlrun/data_types/to_pandas.py,sha256=-ZbJBg00x4xxyqqqu3AVbEh-HaO2--DrChyPuedRhHA,11215
|
|
80
|
-
mlrun/datastore/__init__.py,sha256=
|
|
80
|
+
mlrun/datastore/__init__.py,sha256=y2_NkHUiz9WKJ1XWeUHX-MKErwmIag6nxZ7Z06EcSk0,4180
|
|
81
81
|
mlrun/datastore/alibaba_oss.py,sha256=-RMA4vCE4rar-D57Niy3tY_6bXKHLFpMp28z5YR7-jI,4888
|
|
82
82
|
mlrun/datastore/azure_blob.py,sha256=9qkgrEMXGiuYYcc6b6HkuHlRHDbl0p7tIzeWxAAcEVs,12724
|
|
83
83
|
mlrun/datastore/base.py,sha256=2tGtl1S59SVkk3ZaIZ_Fm2UgAdHtByXUWu3cR36aAYk,26231
|
|
@@ -221,7 +221,7 @@ mlrun/model_monitoring/stream_processing.py,sha256=0eu1Gq1Obq87LFno6eIZ55poXoFae
|
|
|
221
221
|
mlrun/model_monitoring/tracking_policy.py,sha256=sQq956akAQpntkrJwIgFWcEq-JpyVcg0FxgNa4h3V70,5502
|
|
222
222
|
mlrun/model_monitoring/writer.py,sha256=TrBwngRmdwr67De71UCcCFsJOfcqQe8jDp0vkBvGf0o,10177
|
|
223
223
|
mlrun/model_monitoring/applications/__init__.py,sha256=QYvzgCutFdAkzqKPD3mvkX_3c1X4tzd-kW8ojUOE9ic,889
|
|
224
|
-
mlrun/model_monitoring/applications/_application_steps.py,sha256=
|
|
224
|
+
mlrun/model_monitoring/applications/_application_steps.py,sha256=FWgEldIC0Jbg0KLMBIcSNv8uULD1QZ3i7xcC4kEWmrA,7231
|
|
225
225
|
mlrun/model_monitoring/applications/base.py,sha256=uzc14lFlwTJnL0p2VBCzmp-CNoHd73cK_Iz0YHC1KAs,4380
|
|
226
226
|
mlrun/model_monitoring/applications/context.py,sha256=vOZ_ZgUuy5UsNe22-puJSt7TB32HiZtqBdN1hegykuQ,12436
|
|
227
227
|
mlrun/model_monitoring/applications/evidently_base.py,sha256=FSzmoDZP8EiSQ3tq5RmU7kJ6edh8bWaKQh0rBORjODY,5099
|
|
@@ -243,9 +243,9 @@ mlrun/model_monitoring/db/tsdb/__init__.py,sha256=Zqh_27I2YAEHk9nl0Z6lUxP7VEfrgr
|
|
|
243
243
|
mlrun/model_monitoring/db/tsdb/base.py,sha256=X89X763sDrShfRXE1N-p8k97E8NBs7O1QJFiO-CffLM,18583
|
|
244
244
|
mlrun/model_monitoring/db/tsdb/helpers.py,sha256=0oUXc4aUkYtP2SGP6jTb3uPPKImIUsVsrb9otX9a7O4,1189
|
|
245
245
|
mlrun/model_monitoring/db/tsdb/tdengine/__init__.py,sha256=vgBdsKaXUURKqIf3M0y4sRatmSVA4CQiJs7J5dcVBkQ,620
|
|
246
|
-
mlrun/model_monitoring/db/tsdb/tdengine/schemas.py,sha256=
|
|
246
|
+
mlrun/model_monitoring/db/tsdb/tdengine/schemas.py,sha256=UOtb-0shOyKxfYnNzI5uNM5fdI9FbbSDGGRuzvgOKO8,10560
|
|
247
247
|
mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py,sha256=Hb0vcCBP-o0ET78mU4P32fnhUL65QZv-pMuv2lnCby4,1586
|
|
248
|
-
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=
|
|
248
|
+
mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py,sha256=ZpYqPLq8l9aRzgAZ-1uxY_T1eRfx2I2_k7mGfKR2vwI,19683
|
|
249
249
|
mlrun/model_monitoring/db/tsdb/v3io/__init__.py,sha256=aL3bfmQsUQ-sbvKGdNihFj8gLCK3mSys0qDcXtYOwgc,616
|
|
250
250
|
mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py,sha256=mbmhN4f_F58ptVjhwoMF6ifZSdnZWhK7x8eNsWS39IA,6217
|
|
251
251
|
mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py,sha256=1H-IBXPNJPRAaxDMGWpUU25QqfR87LpZbJ03vaJkICs,32858
|
|
@@ -269,7 +269,7 @@ mlrun/package/utils/_supported_format.py,sha256=O3LPTvZ6A-nGi6mB2kTzJp2DQ-cCOgnl
|
|
|
269
269
|
mlrun/package/utils/log_hint_utils.py,sha256=40X7oVzCiAIGsTTSON0iYNHj-_1Y4l4SDMThTA85If8,3696
|
|
270
270
|
mlrun/package/utils/type_hint_utils.py,sha256=JYrek6vuN3z7e6MGUD3qBLDfQ03C4puZXNTpDSj-VrM,14695
|
|
271
271
|
mlrun/platforms/__init__.py,sha256=ggSGF7inITs6S-vj9u4S9X_5psgbA0G3GVqf7zu8qYc,2406
|
|
272
|
-
mlrun/platforms/iguazio.py,sha256=
|
|
272
|
+
mlrun/platforms/iguazio.py,sha256=s_I9zf1IiMS7Rv6b7umQm5LBW-4rDdLqzhbWd5Ve0u0,13741
|
|
273
273
|
mlrun/projects/__init__.py,sha256=Lv5rfxyXJrw6WGOWJKhBz66M6t3_zsNMCfUD6waPwx4,1153
|
|
274
274
|
mlrun/projects/operations.py,sha256=gtqSU9OvYOV-b681uQtWgnW7YSnX6qfa1Mt1Xm4f1ZI,19752
|
|
275
275
|
mlrun/projects/pipelines.py,sha256=tJsoqHYJw0jsB9rawUtTHQ71xnT03b_JVyPROPX-EGU,40962
|
|
@@ -311,7 +311,7 @@ mlrun/serving/serving_wrapper.py,sha256=R670-S6PX_d5ER6jiHtRvacuPyFzQH0mEf2K0sBI
|
|
|
311
311
|
mlrun/serving/states.py,sha256=e4QGSAnNq_eLPDoojxkMkw7fLgUST5ea_BQTO7jWsTA,60228
|
|
312
312
|
mlrun/serving/utils.py,sha256=lej7XcUPX1MmHkEOi_0KZRGSpfbmpnE0GK_Sn4zLkHY,4025
|
|
313
313
|
mlrun/serving/v1_serving.py,sha256=by4myxlnwyZ0ijQ5fURilGCK1sUpdQL2Il1VR3Xqpxg,11805
|
|
314
|
-
mlrun/serving/v2_serving.py,sha256
|
|
314
|
+
mlrun/serving/v2_serving.py,sha256=y48sMhSmZwwHAeTaqdeaxeRag3hkZH1nDolx5CS8VbU,26379
|
|
315
315
|
mlrun/track/__init__.py,sha256=LWRUHJt8JyFW17FyNPOVyWd-NXTf1iptzsK9KFj5fuY,765
|
|
316
316
|
mlrun/track/tracker.py,sha256=hSi9sMxB7hhZalt6Q8GXDnK4UoCbXHzKTrpUPC9hZv4,3555
|
|
317
317
|
mlrun/track/tracker_manager.py,sha256=IYBl99I62IC6VCCmG1yt6JoHNOQXa53C4DURJ2sWgio,5726
|
|
@@ -341,11 +341,11 @@ mlrun/utils/notifications/notification/ipython.py,sha256=ZtVL30B_Ha0VGoo4LxO-voT
|
|
|
341
341
|
mlrun/utils/notifications/notification/slack.py,sha256=wqpFGr5BTvFO5KuUSzFfxsgmyU1Ohq7fbrGeNe9TXOk,7006
|
|
342
342
|
mlrun/utils/notifications/notification/webhook.py,sha256=cb9w1Mc8ENfJBdgan7iiVHK9eVls4-R3tUxmXM-P-8I,4746
|
|
343
343
|
mlrun/utils/version/__init__.py,sha256=7kkrB7hEZ3cLXoWj1kPoDwo4MaswsI2JVOBpbKgPAgc,614
|
|
344
|
-
mlrun/utils/version/version.json,sha256=
|
|
344
|
+
mlrun/utils/version/version.json,sha256=HBnwcA02wuGhgIh3CaTs4vcCO7x-p7WJlHFSibfalCM,88
|
|
345
345
|
mlrun/utils/version/version.py,sha256=eEW0tqIAkU9Xifxv8Z9_qsYnNhn3YH7NRAfM-pPLt1g,1878
|
|
346
|
-
mlrun-1.7.
|
|
347
|
-
mlrun-1.7.
|
|
348
|
-
mlrun-1.7.
|
|
349
|
-
mlrun-1.7.
|
|
350
|
-
mlrun-1.7.
|
|
351
|
-
mlrun-1.7.
|
|
346
|
+
mlrun-1.7.1rc1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
347
|
+
mlrun-1.7.1rc1.dist-info/METADATA,sha256=oSXdUATAGXFNENwVMd3w3-VE-igM0Y_fHiHsgWG4xcI,24486
|
|
348
|
+
mlrun-1.7.1rc1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
349
|
+
mlrun-1.7.1rc1.dist-info/entry_points.txt,sha256=1Owd16eAclD5pfRCoJpYC2ZJSyGNTtUr0nCELMioMmU,46
|
|
350
|
+
mlrun-1.7.1rc1.dist-info/top_level.txt,sha256=NObLzw3maSF9wVrgSeYBv-fgnHkAJ1kEkh12DLdd5KM,6
|
|
351
|
+
mlrun-1.7.1rc1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|