mlrun 1.10.0rc7__py3-none-any.whl → 1.10.0rc8__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 +3 -1
- mlrun/common/schemas/background_task.py +5 -0
- mlrun/common/schemas/model_monitoring/__init__.py +2 -0
- mlrun/common/schemas/model_monitoring/constants.py +16 -0
- mlrun/common/schemas/project.py +4 -0
- mlrun/common/schemas/serving.py +2 -0
- mlrun/config.py +11 -22
- mlrun/datastore/utils.py +3 -1
- mlrun/db/base.py +11 -10
- mlrun/db/httpdb.py +97 -25
- mlrun/db/nopdb.py +5 -4
- mlrun/frameworks/tf_keras/__init__.py +4 -4
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +23 -20
- mlrun/frameworks/tf_keras/model_handler.py +69 -9
- mlrun/frameworks/tf_keras/utils.py +12 -1
- mlrun/launcher/base.py +6 -0
- mlrun/launcher/client.py +1 -21
- mlrun/projects/pipelines.py +33 -3
- mlrun/projects/project.py +13 -16
- mlrun/run.py +37 -5
- mlrun/runtimes/nuclio/serving.py +14 -5
- mlrun/serving/__init__.py +2 -0
- mlrun/serving/server.py +156 -26
- mlrun/serving/states.py +215 -18
- mlrun/serving/system_steps.py +391 -0
- mlrun/serving/v2_serving.py +9 -8
- mlrun/utils/helpers.py +18 -0
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/METADATA +8 -8
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/RECORD +34 -33
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc7.dist-info → mlrun-1.10.0rc8.dist-info}/top_level.txt +0 -0
|
@@ -29,7 +29,7 @@ from mlrun.features import Feature
|
|
|
29
29
|
from .._common import without_mlrun_interface
|
|
30
30
|
from .._dl_common import DLModelHandler
|
|
31
31
|
from .mlrun_interface import TFKerasMLRunInterface
|
|
32
|
-
from .utils import TFKerasUtils
|
|
32
|
+
from .utils import TFKerasUtils, is_keras_3
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class TFKerasModelHandler(DLModelHandler):
|
|
@@ -40,8 +40,8 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
40
40
|
# Framework name:
|
|
41
41
|
FRAMEWORK_NAME = "tensorflow.keras"
|
|
42
42
|
|
|
43
|
-
# Declare a type of
|
|
44
|
-
IOSample = Union[tf.Tensor, tf.TensorSpec, np.ndarray]
|
|
43
|
+
# Declare a type of input sample (only from keras v3 there is a KerasTensor type):
|
|
44
|
+
IOSample = Union[tf.Tensor, tf.TensorSpec, "keras.KerasTensor", np.ndarray]
|
|
45
45
|
|
|
46
46
|
class ModelFormats:
|
|
47
47
|
"""
|
|
@@ -49,9 +49,19 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
49
49
|
"""
|
|
50
50
|
|
|
51
51
|
SAVED_MODEL = "SavedModel"
|
|
52
|
+
KERAS = "keras"
|
|
52
53
|
H5 = "h5"
|
|
53
54
|
JSON_ARCHITECTURE_H5_WEIGHTS = "json_h5"
|
|
54
55
|
|
|
56
|
+
@classmethod
|
|
57
|
+
def default(cls) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Get the default model format to use for saving and loading the model based on the keras version.
|
|
60
|
+
|
|
61
|
+
:return: The default model format to use.
|
|
62
|
+
"""
|
|
63
|
+
return cls.KERAS if is_keras_3() else cls.SAVED_MODEL
|
|
64
|
+
|
|
55
65
|
class _LabelKeys:
|
|
56
66
|
"""
|
|
57
67
|
Required labels keys to log with the model.
|
|
@@ -65,7 +75,7 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
65
75
|
model: keras.Model = None,
|
|
66
76
|
model_path: Optional[str] = None,
|
|
67
77
|
model_name: Optional[str] = None,
|
|
68
|
-
model_format: str =
|
|
78
|
+
model_format: Optional[str] = None,
|
|
69
79
|
context: mlrun.MLClientCtx = None,
|
|
70
80
|
modules_map: Optional[
|
|
71
81
|
Union[dict[str, Union[None, str, list[str]]], str]
|
|
@@ -98,7 +108,7 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
98
108
|
* If given a loaded model object and the model name is None, the name will be
|
|
99
109
|
set to the model's object name / class.
|
|
100
110
|
:param model_format: The format to use for saving and loading the model. Should be passed as a
|
|
101
|
-
member of the class 'ModelFormats'.
|
|
111
|
+
member of the class 'ModelFormats'.
|
|
102
112
|
:param context: MLRun context to work with for logging the model.
|
|
103
113
|
:param modules_map: A dictionary of all the modules required for loading the model. Each key
|
|
104
114
|
is a path to a module and its value is the object name to import from it. All
|
|
@@ -144,8 +154,11 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
144
154
|
* 'save_traces' parameter was miss-used.
|
|
145
155
|
"""
|
|
146
156
|
# Validate given format:
|
|
157
|
+
if not model_format:
|
|
158
|
+
model_format = TFKerasModelHandler.ModelFormats.default()
|
|
147
159
|
if model_format not in [
|
|
148
160
|
TFKerasModelHandler.ModelFormats.SAVED_MODEL,
|
|
161
|
+
TFKerasModelHandler.ModelFormats.KERAS,
|
|
149
162
|
TFKerasModelHandler.ModelFormats.H5,
|
|
150
163
|
TFKerasModelHandler.ModelFormats.JSON_ARCHITECTURE_H5_WEIGHTS,
|
|
151
164
|
]:
|
|
@@ -153,6 +166,22 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
153
166
|
f"Unrecognized model format: '{model_format}'. Please use one of the class members of "
|
|
154
167
|
"'TFKerasModelHandler.ModelFormats'"
|
|
155
168
|
)
|
|
169
|
+
if not is_keras_3():
|
|
170
|
+
if model_format == TFKerasModelHandler.ModelFormats.KERAS:
|
|
171
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
172
|
+
"The 'keras' model format is only supported in Keras 3.0.0 and above. "
|
|
173
|
+
f"Current version is {keras.__version__}."
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
if (
|
|
177
|
+
model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL
|
|
178
|
+
or model_format
|
|
179
|
+
== TFKerasModelHandler.ModelFormats.JSON_ARCHITECTURE_H5_WEIGHTS
|
|
180
|
+
):
|
|
181
|
+
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
182
|
+
f"The '{model_format}' model format is not supported in Keras 3.0.0 and above. "
|
|
183
|
+
f"Current version is {keras.__version__}."
|
|
184
|
+
)
|
|
156
185
|
|
|
157
186
|
# Validate 'save_traces':
|
|
158
187
|
if save_traces:
|
|
@@ -239,11 +268,19 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
239
268
|
self._model_file = f"{self._model_name}.h5"
|
|
240
269
|
self._model.save(self._model_file)
|
|
241
270
|
|
|
271
|
+
# ModelFormats.keras - Save as a keras file:
|
|
272
|
+
elif self._model_format == self.ModelFormats.KERAS:
|
|
273
|
+
self._model_file = f"{self._model_name}.keras"
|
|
274
|
+
self._model.save(self._model_file)
|
|
275
|
+
|
|
242
276
|
# ModelFormats.SAVED_MODEL - Save as a SavedModel directory and zip its file:
|
|
243
277
|
elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
|
|
244
278
|
# Save it in a SavedModel format directory:
|
|
279
|
+
# Note: Using keras>=3.0.0 can save in this format via `model.export` but then it won't be able to load it
|
|
280
|
+
# back, only for inference. So, we use the `save` method instead for keras 2 and validate the user won't use
|
|
281
|
+
# keras 3 and this model format.
|
|
245
282
|
if self._save_traces is True:
|
|
246
|
-
# Save traces can only be used in versions >= 2.4, so only if
|
|
283
|
+
# Save traces can only be used in versions >= 2.4, so only if it's true, we use it in the call:
|
|
247
284
|
self._model.save(self._model_name, save_traces=self._save_traces)
|
|
248
285
|
else:
|
|
249
286
|
self._model.save(self._model_name)
|
|
@@ -303,6 +340,12 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
303
340
|
self._model_file, custom_objects=self._custom_objects
|
|
304
341
|
)
|
|
305
342
|
|
|
343
|
+
# ModelFormats.KERAS - Load from a keras file:
|
|
344
|
+
elif self._model_format == TFKerasModelHandler.ModelFormats.KERAS:
|
|
345
|
+
self._model = keras.models.load_model(
|
|
346
|
+
self._model_file, custom_objects=self._custom_objects
|
|
347
|
+
)
|
|
348
|
+
|
|
306
349
|
# ModelFormats.SAVED_MODEL - Load from a SavedModel directory:
|
|
307
350
|
elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
|
|
308
351
|
self._model = keras.models.load_model(
|
|
@@ -434,7 +477,10 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
434
477
|
)
|
|
435
478
|
|
|
436
479
|
# Read the inputs:
|
|
437
|
-
input_signature = [
|
|
480
|
+
input_signature = [
|
|
481
|
+
getattr(input_layer, "type_spec", input_layer)
|
|
482
|
+
for input_layer in self._model.inputs
|
|
483
|
+
]
|
|
438
484
|
|
|
439
485
|
# Set the inputs:
|
|
440
486
|
self.set_inputs(from_sample=input_signature)
|
|
@@ -453,7 +499,8 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
453
499
|
|
|
454
500
|
# Read the outputs:
|
|
455
501
|
output_signature = [
|
|
456
|
-
output_layer
|
|
502
|
+
getattr(output_layer, "type_spec", output_layer)
|
|
503
|
+
for output_layer in self._model.outputs
|
|
457
504
|
]
|
|
458
505
|
|
|
459
506
|
# Set the outputs:
|
|
@@ -509,6 +556,17 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
509
556
|
f"'{self._model_path}'"
|
|
510
557
|
)
|
|
511
558
|
|
|
559
|
+
# ModelFormats.KERAS - Get the keras model file:
|
|
560
|
+
elif self._model_format == TFKerasModelHandler.ModelFormats.KERAS:
|
|
561
|
+
self._model_file = os.path.join(
|
|
562
|
+
self._model_path, f"{self._model_name}.keras"
|
|
563
|
+
)
|
|
564
|
+
if not os.path.exists(self._model_file):
|
|
565
|
+
raise mlrun.errors.MLRunNotFoundError(
|
|
566
|
+
f"The model file '{self._model_name}.keras' was not found within the given 'model_path': "
|
|
567
|
+
f"'{self._model_path}'"
|
|
568
|
+
)
|
|
569
|
+
|
|
512
570
|
# ModelFormats.SAVED_MODEL - Get the zip file and extract it, or simply locate the directory:
|
|
513
571
|
elif self._model_format == TFKerasModelHandler.ModelFormats.SAVED_MODEL:
|
|
514
572
|
self._model_file = os.path.join(self._model_path, f"{self._model_name}.zip")
|
|
@@ -559,7 +617,9 @@ class TFKerasModelHandler(DLModelHandler):
|
|
|
559
617
|
# Supported types:
|
|
560
618
|
if isinstance(sample, np.ndarray):
|
|
561
619
|
return super()._read_sample(sample=sample)
|
|
562
|
-
elif isinstance(sample, tf.TensorSpec)
|
|
620
|
+
elif isinstance(sample, tf.TensorSpec) or (
|
|
621
|
+
is_keras_3() and isinstance(sample, keras.KerasTensor)
|
|
622
|
+
):
|
|
563
623
|
return Feature(
|
|
564
624
|
name=sample.name,
|
|
565
625
|
value_type=TFKerasUtils.convert_tf_dtype_to_value_type(
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
15
14
|
import tensorflow as tf
|
|
15
|
+
from packaging import version
|
|
16
16
|
from tensorflow import keras
|
|
17
17
|
|
|
18
18
|
import mlrun
|
|
@@ -117,3 +117,14 @@ class TFKerasUtils(DLUtils):
|
|
|
117
117
|
raise mlrun.errors.MLRunInvalidArgumentError(
|
|
118
118
|
f"MLRun value type is not supporting the given tensorflow data type: '{tf_dtype}'."
|
|
119
119
|
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def is_keras_3() -> bool:
|
|
123
|
+
"""
|
|
124
|
+
Check if the current Keras version is 3.x.
|
|
125
|
+
|
|
126
|
+
:return: True if Keras version is 3.x, False otherwise.
|
|
127
|
+
"""
|
|
128
|
+
return hasattr(keras, "__version__") and version.parse(
|
|
129
|
+
keras.__version__
|
|
130
|
+
) >= version.parse("3.0.0")
|
mlrun/launcher/base.py
CHANGED
|
@@ -148,6 +148,12 @@ class BaseLauncher(abc.ABC):
|
|
|
148
148
|
self._validate_run_params(run.spec.parameters)
|
|
149
149
|
self._validate_output_path(runtime, run)
|
|
150
150
|
|
|
151
|
+
for image in [
|
|
152
|
+
runtime.spec.image,
|
|
153
|
+
getattr(runtime.spec.build, "base_image", None),
|
|
154
|
+
]:
|
|
155
|
+
mlrun.utils.helpers.warn_on_deprecated_image(image)
|
|
156
|
+
|
|
151
157
|
@staticmethod
|
|
152
158
|
def _validate_output_path(
|
|
153
159
|
runtime: "mlrun.runtimes.BaseRuntime",
|
mlrun/launcher/client.py
CHANGED
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
import abc
|
|
15
|
-
import warnings
|
|
16
15
|
from typing import Optional
|
|
17
16
|
|
|
18
17
|
import IPython.display
|
|
@@ -63,26 +62,7 @@ class ClientBaseLauncher(launcher.BaseLauncher, abc.ABC):
|
|
|
63
62
|
):
|
|
64
63
|
image = mlrun.mlconf.function_defaults.image_by_kind.to_dict()[runtime.kind]
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
if image and "mlrun/ml-base" in image:
|
|
68
|
-
client_version = mlrun.utils.version.Version().get()["version"]
|
|
69
|
-
auto_replaced = mlrun.utils.validate_component_version_compatibility(
|
|
70
|
-
"mlrun-client", "1.10.0", mlrun_client_version=client_version
|
|
71
|
-
)
|
|
72
|
-
message = (
|
|
73
|
-
"'mlrun/ml-base' image is deprecated in 1.10.0 and will be removed in 1.12.0, "
|
|
74
|
-
"use 'mlrun/mlrun' instead."
|
|
75
|
-
)
|
|
76
|
-
if auto_replaced:
|
|
77
|
-
message += (
|
|
78
|
-
" Since your client version is >= 1.10.0, the image will be automatically "
|
|
79
|
-
"replaced with mlrun/mlrun."
|
|
80
|
-
)
|
|
81
|
-
warnings.warn(
|
|
82
|
-
message,
|
|
83
|
-
# TODO: Remove this in 1.12.0
|
|
84
|
-
FutureWarning,
|
|
85
|
-
)
|
|
65
|
+
mlrun.utils.helpers.warn_on_deprecated_image(image)
|
|
86
66
|
|
|
87
67
|
# TODO: need a better way to decide whether a function requires a build
|
|
88
68
|
if require_build and image and not runtime.spec.build.base_image:
|
mlrun/projects/pipelines.py
CHANGED
|
@@ -39,7 +39,12 @@ from mlrun.utils import (
|
|
|
39
39
|
|
|
40
40
|
from ..common.helpers import parse_versioned_object_uri
|
|
41
41
|
from ..config import config
|
|
42
|
-
from ..run import
|
|
42
|
+
from ..run import (
|
|
43
|
+
_run_pipeline,
|
|
44
|
+
retry_pipeline,
|
|
45
|
+
terminate_pipeline,
|
|
46
|
+
wait_for_pipeline_completion,
|
|
47
|
+
)
|
|
43
48
|
from ..runtimes.pod import AutoMountType
|
|
44
49
|
|
|
45
50
|
|
|
@@ -696,6 +701,24 @@ class _KFPRunner(_PipelineRunner):
|
|
|
696
701
|
)
|
|
697
702
|
return run_id
|
|
698
703
|
|
|
704
|
+
@classmethod
|
|
705
|
+
def terminate(
|
|
706
|
+
cls,
|
|
707
|
+
run: "_PipelineRunStatus",
|
|
708
|
+
project: typing.Optional["mlrun.projects.MlrunProject"] = None,
|
|
709
|
+
) -> str:
|
|
710
|
+
project_name = project.metadata.name if project else ""
|
|
711
|
+
logger.info(
|
|
712
|
+
"Terminating pipeline",
|
|
713
|
+
run_id=run.run_id,
|
|
714
|
+
project=project_name,
|
|
715
|
+
)
|
|
716
|
+
run_id = terminate_pipeline(
|
|
717
|
+
run.run_id,
|
|
718
|
+
project=project_name,
|
|
719
|
+
)
|
|
720
|
+
return run_id
|
|
721
|
+
|
|
699
722
|
@staticmethod
|
|
700
723
|
def wait_for_completion(
|
|
701
724
|
run: "_PipelineRunStatus",
|
|
@@ -1145,7 +1168,9 @@ def load_and_run_workflow(
|
|
|
1145
1168
|
notification.when = ["running"]
|
|
1146
1169
|
|
|
1147
1170
|
workflow_log_message = workflow_name or workflow_path
|
|
1148
|
-
context.logger.info(
|
|
1171
|
+
context.logger.info(
|
|
1172
|
+
"Running workflow from remote", workflow_log_message=workflow_log_message
|
|
1173
|
+
)
|
|
1149
1174
|
run = project.run(
|
|
1150
1175
|
name=workflow_name,
|
|
1151
1176
|
workflow_path=workflow_path,
|
|
@@ -1162,6 +1187,11 @@ def load_and_run_workflow(
|
|
|
1162
1187
|
notifications=start_notifications,
|
|
1163
1188
|
context=context,
|
|
1164
1189
|
)
|
|
1190
|
+
# Patch the current run object (the workflow-runner) with the workflow-id label
|
|
1191
|
+
context.logger.info(
|
|
1192
|
+
"Associating workflow-runner with workflow ID", run_id=run.run_id
|
|
1193
|
+
)
|
|
1194
|
+
context.set_label("workflow-id", run.run_id)
|
|
1165
1195
|
context.log_result(key="workflow_id", value=run.run_id)
|
|
1166
1196
|
context.log_result(key="engine", value=run._engine.engine, commit=True)
|
|
1167
1197
|
|
|
@@ -1321,4 +1351,4 @@ def import_remote_project(
|
|
|
1321
1351
|
sync_functions=True,
|
|
1322
1352
|
)
|
|
1323
1353
|
|
|
1324
|
-
context.logger.info(
|
|
1354
|
+
context.logger.info("Loaded project successfully", project_name=project.name)
|
mlrun/projects/project.py
CHANGED
|
@@ -2518,7 +2518,6 @@ class MlrunProject(ModelObj):
|
|
|
2518
2518
|
|
|
2519
2519
|
def enable_model_monitoring(
|
|
2520
2520
|
self,
|
|
2521
|
-
default_controller_image: str = "mlrun/mlrun",
|
|
2522
2521
|
base_period: int = 10,
|
|
2523
2522
|
image: str = "mlrun/mlrun",
|
|
2524
2523
|
*,
|
|
@@ -2534,7 +2533,6 @@ class MlrunProject(ModelObj):
|
|
|
2534
2533
|
The stream function goal is to monitor the log of the data stream. It is triggered when a new log entry
|
|
2535
2534
|
is detected. It processes the new events into statistics that are then written to statistics databases.
|
|
2536
2535
|
|
|
2537
|
-
:param default_controller_image: Deprecated.
|
|
2538
2536
|
:param base_period: The time period in minutes in which the model monitoring controller
|
|
2539
2537
|
function is triggered. By default, the base period is 10 minutes
|
|
2540
2538
|
(which is also the minimum value for production environments).
|
|
@@ -2562,14 +2560,6 @@ class MlrunProject(ModelObj):
|
|
|
2562
2560
|
background, including the histogram data drift app if selected.
|
|
2563
2561
|
:param fetch_credentials_from_sys_config: If true, fetch the credentials from the system configuration.
|
|
2564
2562
|
"""
|
|
2565
|
-
if default_controller_image != "mlrun/mlrun":
|
|
2566
|
-
# TODO: Remove this in 1.10.0
|
|
2567
|
-
warnings.warn(
|
|
2568
|
-
"'default_controller_image' is deprecated in 1.7.0 and will be removed in 1.10.0, "
|
|
2569
|
-
"use 'image' instead",
|
|
2570
|
-
FutureWarning,
|
|
2571
|
-
)
|
|
2572
|
-
image = default_controller_image
|
|
2573
2563
|
if base_period < 10:
|
|
2574
2564
|
logger.warn(
|
|
2575
2565
|
"enable_model_monitoring: 'base_period' < 10 minutes is not supported in production environments",
|
|
@@ -3848,7 +3838,8 @@ class MlrunProject(ModelObj):
|
|
|
3848
3838
|
)
|
|
3849
3839
|
|
|
3850
3840
|
The replication factor and timeout configuration might need to be adjusted according to your Confluent cluster
|
|
3851
|
-
type and settings.
|
|
3841
|
+
type and settings. Nuclio annotations for the model monitoring infrastructure and application functions are
|
|
3842
|
+
supported through ``kwargs_public={"nuclio_annotations": {...}, ...}``.
|
|
3852
3843
|
|
|
3853
3844
|
:param tsdb_profile_name: The datastore profile name of the time-series database to be used in model
|
|
3854
3845
|
monitoring. The supported profiles are:
|
|
@@ -4278,11 +4269,17 @@ class MlrunProject(ModelObj):
|
|
|
4278
4269
|
function = mlrun.new_function("mlrun--project--image--builder", kind="job")
|
|
4279
4270
|
|
|
4280
4271
|
if self.spec.source and not self.spec.load_source_on_run:
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4272
|
+
if self.spec.source.startswith("db://"):
|
|
4273
|
+
logger.debug(
|
|
4274
|
+
"Project source is 'db://', which refers to metadata stored in the MLRun DB."
|
|
4275
|
+
" Skipping source archive setup for image build"
|
|
4276
|
+
)
|
|
4277
|
+
else:
|
|
4278
|
+
function.with_source_archive(
|
|
4279
|
+
source=self.spec.source,
|
|
4280
|
+
target_dir=target_dir,
|
|
4281
|
+
pull_at_runtime=False,
|
|
4282
|
+
)
|
|
4286
4283
|
|
|
4287
4284
|
build = self.spec.build
|
|
4288
4285
|
result = self.build_function(
|
mlrun/run.py
CHANGED
|
@@ -894,7 +894,6 @@ def _run_pipeline(
|
|
|
894
894
|
def retry_pipeline(
|
|
895
895
|
run_id: str,
|
|
896
896
|
project: str,
|
|
897
|
-
namespace: Optional[str] = None,
|
|
898
897
|
) -> str:
|
|
899
898
|
"""Retry a pipeline run.
|
|
900
899
|
|
|
@@ -903,7 +902,6 @@ def retry_pipeline(
|
|
|
903
902
|
|
|
904
903
|
:param run_id: ID of the pipeline run to retry.
|
|
905
904
|
:param project: name of the project associated with the pipeline run.
|
|
906
|
-
:param namespace: Optional; Kubernetes namespace to use if not the default.
|
|
907
905
|
|
|
908
906
|
:returns: ID of the retried pipeline run or the ID of a cloned run if the original run is not retryable.
|
|
909
907
|
:raises ValueError: If access to the remote API service is not available.
|
|
@@ -918,7 +916,6 @@ def retry_pipeline(
|
|
|
918
916
|
pipeline_run_id = mldb.retry_pipeline(
|
|
919
917
|
run_id=run_id,
|
|
920
918
|
project=project,
|
|
921
|
-
namespace=namespace,
|
|
922
919
|
)
|
|
923
920
|
if pipeline_run_id == run_id:
|
|
924
921
|
logger.info(
|
|
@@ -931,6 +928,35 @@ def retry_pipeline(
|
|
|
931
928
|
return pipeline_run_id
|
|
932
929
|
|
|
933
930
|
|
|
931
|
+
def terminate_pipeline(
|
|
932
|
+
run_id: str,
|
|
933
|
+
project: str,
|
|
934
|
+
) -> str:
|
|
935
|
+
"""Terminate a pipeline run.
|
|
936
|
+
|
|
937
|
+
This function terminates a running pipeline with the specified run ID. If the run is not in a
|
|
938
|
+
terminable state, an error is raised.
|
|
939
|
+
|
|
940
|
+
:param run_id: ID of the pipeline run to terminate.
|
|
941
|
+
:param project: name of the project associated with the pipeline run.
|
|
942
|
+
|
|
943
|
+
:returns: ID of the terminate pipeline run background task.
|
|
944
|
+
:raises ValueError: If access to the remote API service is not available.
|
|
945
|
+
"""
|
|
946
|
+
mldb = mlrun.db.get_run_db()
|
|
947
|
+
if mldb.kind != "http":
|
|
948
|
+
raise ValueError(
|
|
949
|
+
"Terminating a pipeline requires access to remote API service. "
|
|
950
|
+
"Please set the dbpath URL."
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
pipeline_run_task = mldb.terminate_pipeline(
|
|
954
|
+
run_id=run_id,
|
|
955
|
+
project=project,
|
|
956
|
+
)
|
|
957
|
+
return pipeline_run_task["metadata"]["id"]
|
|
958
|
+
|
|
959
|
+
|
|
934
960
|
def wait_for_pipeline_completion(
|
|
935
961
|
run_id,
|
|
936
962
|
timeout=60 * 60,
|
|
@@ -997,7 +1023,10 @@ def wait_for_pipeline_completion(
|
|
|
997
1023
|
_wait_for_pipeline_completion,
|
|
998
1024
|
)
|
|
999
1025
|
else:
|
|
1000
|
-
client = mlrun_pipelines.utils.get_client(
|
|
1026
|
+
client = mlrun_pipelines.utils.get_client(
|
|
1027
|
+
logger=logger,
|
|
1028
|
+
namespace=namespace,
|
|
1029
|
+
)
|
|
1001
1030
|
resp = client.wait_for_run_completion(run_id, timeout)
|
|
1002
1031
|
if resp:
|
|
1003
1032
|
resp = resp.to_dict()
|
|
@@ -1058,7 +1087,10 @@ def get_pipeline(
|
|
|
1058
1087
|
)
|
|
1059
1088
|
|
|
1060
1089
|
else:
|
|
1061
|
-
client = mlrun_pipelines.utils.get_client(
|
|
1090
|
+
client = mlrun_pipelines.utils.get_client(
|
|
1091
|
+
logger=logger,
|
|
1092
|
+
namespace=namespace,
|
|
1093
|
+
)
|
|
1062
1094
|
resp = client.get_run(run_id)
|
|
1063
1095
|
if resp:
|
|
1064
1096
|
resp = resp.to_dict()
|
mlrun/runtimes/nuclio/serving.py
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
import copy
|
|
15
14
|
import json
|
|
16
15
|
import os
|
|
17
16
|
import warnings
|
|
@@ -482,6 +481,7 @@ class ServingRuntime(RemoteRuntime):
|
|
|
482
481
|
state = TaskStep(
|
|
483
482
|
class_name,
|
|
484
483
|
class_args,
|
|
484
|
+
name=key,
|
|
485
485
|
handler=handler,
|
|
486
486
|
function=child_function,
|
|
487
487
|
model_endpoint_creation_strategy=creation_strategy,
|
|
@@ -751,13 +751,10 @@ class ServingRuntime(RemoteRuntime):
|
|
|
751
751
|
set_paths(workdir)
|
|
752
752
|
os.chdir(workdir)
|
|
753
753
|
|
|
754
|
-
system_graph = None
|
|
755
|
-
if isinstance(self.spec.graph, RootFlowStep):
|
|
756
|
-
system_graph = add_system_steps_to_graph(copy.deepcopy(self.spec.graph))
|
|
757
754
|
server = create_graph_server(
|
|
758
755
|
parameters=self.spec.parameters,
|
|
759
756
|
load_mode=self.spec.load_mode,
|
|
760
|
-
graph=
|
|
757
|
+
graph=self.spec.graph,
|
|
761
758
|
verbose=self.verbose,
|
|
762
759
|
current_function=current_function,
|
|
763
760
|
graph_initializer=self.spec.graph_initializer,
|
|
@@ -778,6 +775,18 @@ class ServingRuntime(RemoteRuntime):
|
|
|
778
775
|
monitoring_mock=self.spec.track_models,
|
|
779
776
|
)
|
|
780
777
|
|
|
778
|
+
if (
|
|
779
|
+
isinstance(self.spec.graph, RootFlowStep)
|
|
780
|
+
and self.spec.graph.include_monitored_step()
|
|
781
|
+
):
|
|
782
|
+
server.graph = add_system_steps_to_graph(
|
|
783
|
+
server.project,
|
|
784
|
+
server.graph,
|
|
785
|
+
self.spec.track_models,
|
|
786
|
+
server.context,
|
|
787
|
+
self.spec,
|
|
788
|
+
)
|
|
789
|
+
|
|
781
790
|
if workdir:
|
|
782
791
|
os.chdir(old_workdir)
|
|
783
792
|
|
mlrun/serving/__init__.py
CHANGED
|
@@ -27,6 +27,7 @@ __all__ = [
|
|
|
27
27
|
"ModelRunner",
|
|
28
28
|
"Model",
|
|
29
29
|
"ModelSelector",
|
|
30
|
+
"MonitoredStep",
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
from .routers import ModelRouter, VotingEnsemble # noqa
|
|
@@ -45,6 +46,7 @@ from .states import (
|
|
|
45
46
|
ModelRunner,
|
|
46
47
|
Model,
|
|
47
48
|
ModelSelector,
|
|
49
|
+
MonitoredStep,
|
|
48
50
|
) # noqa
|
|
49
51
|
from .v1_serving import MLModelServer, new_v1_model_server # noqa
|
|
50
52
|
from .v2_serving import V2ModelServer # noqa
|