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.

Files changed (75) hide show
  1. mlrun/__init__.py +5 -3
  2. mlrun/alerts/alert.py +129 -2
  3. mlrun/artifacts/__init__.py +1 -1
  4. mlrun/artifacts/base.py +12 -1
  5. mlrun/artifacts/document.py +59 -38
  6. mlrun/common/constants.py +1 -0
  7. mlrun/common/model_monitoring/__init__.py +0 -2
  8. mlrun/common/model_monitoring/helpers.py +0 -28
  9. mlrun/common/schemas/__init__.py +2 -4
  10. mlrun/common/schemas/alert.py +80 -1
  11. mlrun/common/schemas/artifact.py +4 -0
  12. mlrun/common/schemas/client_spec.py +0 -1
  13. mlrun/common/schemas/model_monitoring/__init__.py +0 -6
  14. mlrun/common/schemas/model_monitoring/constants.py +11 -9
  15. mlrun/common/schemas/model_monitoring/model_endpoints.py +77 -149
  16. mlrun/common/schemas/notification.py +6 -0
  17. mlrun/common/schemas/project.py +3 -0
  18. mlrun/config.py +2 -3
  19. mlrun/datastore/datastore_profile.py +57 -17
  20. mlrun/datastore/sources.py +1 -2
  21. mlrun/datastore/vectorstore.py +67 -59
  22. mlrun/db/base.py +29 -19
  23. mlrun/db/factory.py +0 -3
  24. mlrun/db/httpdb.py +224 -161
  25. mlrun/db/nopdb.py +36 -17
  26. mlrun/execution.py +46 -32
  27. mlrun/feature_store/api.py +1 -0
  28. mlrun/model.py +7 -0
  29. mlrun/model_monitoring/__init__.py +3 -2
  30. mlrun/model_monitoring/api.py +55 -53
  31. mlrun/model_monitoring/applications/_application_steps.py +4 -2
  32. mlrun/model_monitoring/applications/base.py +165 -6
  33. mlrun/model_monitoring/applications/context.py +88 -37
  34. mlrun/model_monitoring/applications/evidently_base.py +0 -1
  35. mlrun/model_monitoring/applications/histogram_data_drift.py +3 -7
  36. mlrun/model_monitoring/controller.py +43 -37
  37. mlrun/model_monitoring/db/__init__.py +0 -2
  38. mlrun/model_monitoring/db/tsdb/base.py +2 -1
  39. mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +2 -1
  40. mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +43 -0
  41. mlrun/model_monitoring/helpers.py +79 -66
  42. mlrun/model_monitoring/stream_processing.py +83 -270
  43. mlrun/model_monitoring/writer.py +1 -10
  44. mlrun/projects/pipelines.py +37 -1
  45. mlrun/projects/project.py +171 -74
  46. mlrun/run.py +40 -0
  47. mlrun/runtimes/nuclio/function.py +7 -6
  48. mlrun/runtimes/nuclio/serving.py +9 -2
  49. mlrun/serving/routers.py +158 -145
  50. mlrun/serving/server.py +6 -0
  51. mlrun/serving/states.py +21 -7
  52. mlrun/serving/v2_serving.py +70 -61
  53. mlrun/utils/helpers.py +14 -30
  54. mlrun/utils/notifications/notification/mail.py +36 -9
  55. mlrun/utils/notifications/notification_pusher.py +43 -18
  56. mlrun/utils/version/version.json +2 -2
  57. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/METADATA +5 -4
  58. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/RECORD +62 -75
  59. mlrun/common/schemas/model_monitoring/model_endpoint_v2.py +0 -149
  60. mlrun/model_monitoring/db/stores/__init__.py +0 -136
  61. mlrun/model_monitoring/db/stores/base/__init__.py +0 -15
  62. mlrun/model_monitoring/db/stores/base/store.py +0 -154
  63. mlrun/model_monitoring/db/stores/sqldb/__init__.py +0 -13
  64. mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +0 -46
  65. mlrun/model_monitoring/db/stores/sqldb/models/base.py +0 -93
  66. mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +0 -47
  67. mlrun/model_monitoring/db/stores/sqldb/models/sqlite.py +0 -25
  68. mlrun/model_monitoring/db/stores/sqldb/sql_store.py +0 -408
  69. mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +0 -13
  70. mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +0 -464
  71. mlrun/model_monitoring/model_endpoint.py +0 -120
  72. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/LICENSE +0 -0
  73. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/WHEEL +0 -0
  74. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/entry_points.txt +0 -0
  75. {mlrun-1.8.0rc4.dist-info → mlrun-1.8.0rc7.dist-info}/top_level.txt +0 -0
@@ -55,12 +55,6 @@ from .grafana import (
55
55
  GrafanaTable,
56
56
  GrafanaTimeSeriesTarget,
57
57
  )
58
- from .model_endpoint_v2 import (
59
- ModelEndpointV2,
60
- ModelEndpointV2Metadata,
61
- ModelEndpointV2Spec,
62
- ModelEndpointV2Status,
63
- )
64
58
  from .model_endpoints import (
65
59
  Features,
66
60
  FeatureValues,
@@ -41,6 +41,7 @@ class ModelEndpointSchema(MonitoringStrEnum):
41
41
 
42
42
  # spec
43
43
  FUNCTION_NAME = "function_name"
44
+ FUNCTION_TAG = "function_tag"
44
45
  FUNCTION_UID = "function_uid"
45
46
  MODEL_NAME = "model_name"
46
47
  MODEL_TAG = "model_tag"
@@ -48,23 +49,23 @@ class ModelEndpointSchema(MonitoringStrEnum):
48
49
  MODEL_UID = "model_uid"
49
50
  FEATURE_NAMES = "feature_names"
50
51
  LABEL_NAMES = "label_names"
51
-
52
- # status
53
- STATE = "state"
54
- MONITORING_MODE = "monitoring_mode"
52
+ FEATURE_STATS = "feature_stats"
55
53
  MONITORING_FEATURE_SET_URI = "monitoring_feature_set_uri"
56
54
  CHILDREN = "children"
57
55
  CHILDREN_UIDS = "children_uids"
58
- FIRST_REQUEST = "first_request"
59
56
  FUNCTION_URI = "function_uri"
60
57
  MODEL_URI = "model_uri"
61
58
 
59
+ # status
60
+ STATE = "state"
61
+ MONITORING_MODE = "monitoring_mode"
62
+ FIRST_REQUEST = "first_request"
63
+
62
64
  # status - operative
63
65
  LAST_REQUEST = "last_request"
64
- DRIFT_STATUS = "drift_status"
66
+ RESULT_STATUS = "result_status"
65
67
  AVG_LATENCY = "avg_latency"
66
68
  ERROR_COUNT = "error_count"
67
- FEATURE_STATS = "feature_stats"
68
69
  CURRENT_STATS = "current_stats"
69
70
  DRIFT_MEASURES = "drift_measures"
70
71
 
@@ -80,6 +81,7 @@ class EventFieldType:
80
81
  TIMESTAMP = "timestamp"
81
82
  # `endpoint_id` is deprecated as a field in the model endpoint schema since 1.3.1, replaced by `uid`.
82
83
  ENDPOINT_ID = "endpoint_id"
84
+ ENDPOINT_NAME = "endpoint_name"
83
85
  UID = "uid"
84
86
  ENDPOINT_TYPE = "endpoint_type"
85
87
  REQUEST_ID = "request_id"
@@ -148,10 +150,12 @@ class ApplicationEvent:
148
150
  START_INFER_TIME = "start_infer_time"
149
151
  END_INFER_TIME = "end_infer_time"
150
152
  ENDPOINT_ID = "endpoint_id"
153
+ ENDPOINT_NAME = "endpoint_name"
151
154
  OUTPUT_STREAM_URI = "output_stream_uri"
152
155
 
153
156
 
154
157
  class WriterEvent(MonitoringStrEnum):
158
+ ENDPOINT_NAME = "endpoint_name"
155
159
  APPLICATION_NAME = "application_name"
156
160
  ENDPOINT_ID = "endpoint_id"
157
161
  START_INFER_TIME = "start_infer_time"
@@ -222,7 +226,6 @@ class TSDBTarget(MonitoringStrEnum):
222
226
 
223
227
 
224
228
  class ProjectSecretKeys:
225
- ENDPOINT_STORE_CONNECTION = "MODEL_MONITORING_ENDPOINT_STORE_CONNECTION"
226
229
  ACCESS_KEY = "MODEL_MONITORING_ACCESS_KEY"
227
230
  STREAM_PATH = "STREAM_PATH"
228
231
  TSDB_CONNECTION = "TSDB_CONNECTION"
@@ -230,7 +233,6 @@ class ProjectSecretKeys:
230
233
  @classmethod
231
234
  def mandatory_secrets(cls):
232
235
  return [
233
- cls.ENDPOINT_STORE_CONNECTION,
234
236
  cls.STREAM_PATH,
235
237
  cls.TSDB_CONNECTION,
236
238
  ]
@@ -11,27 +11,22 @@
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
- import enum
14
+ import abc
16
15
  import json
17
16
  from datetime import datetime
18
17
  from typing import Any, NamedTuple, Optional, TypeVar
19
18
 
20
- from pydantic.v1 import BaseModel, Extra, Field, constr, validator
19
+ from pydantic.v1 import BaseModel, Field, constr
21
20
 
22
21
  # TODO: remove the unused import below after `mlrun.datastore` and `mlrun.utils` usage is removed.
23
22
  # At the moment `make lint` fails if this is removed.
24
- import mlrun.common.model_monitoring
25
-
26
- from ..object import ObjectKind, ObjectSpec, ObjectStatus
23
+ from ..object import ObjectKind, ObjectMetadata, ObjectSpec, ObjectStatus
24
+ from . import ModelEndpointSchema
27
25
  from .constants import (
28
26
  FQN_REGEX,
29
27
  MODEL_ENDPOINT_ID_PATTERN,
30
28
  PROJECT_PATTERN,
31
29
  EndpointType,
32
- EventFieldType,
33
- EventKeyMetrics,
34
- EventLiveStats,
35
30
  ModelEndpointMonitoringMetricType,
36
31
  ModelMonitoringMode,
37
32
  ResultKindApp,
@@ -47,81 +42,6 @@ class ModelMonitoringStoreKinds:
47
42
  EVENTS = "events"
48
43
 
49
44
 
50
- class ModelEndpointMetadata(BaseModel):
51
- project: constr(regex=PROJECT_PATTERN)
52
- uid: constr(regex=MODEL_ENDPOINT_ID_PATTERN)
53
- labels: Optional[dict] = {}
54
-
55
- class Config:
56
- extra = Extra.allow
57
-
58
- @classmethod
59
- def from_flat_dict(
60
- cls, endpoint_dict: dict, json_parse_values: Optional[list] = None
61
- ):
62
- """Create a `ModelEndpointMetadata` object from an endpoint dictionary
63
-
64
- :param endpoint_dict: Model endpoint dictionary.
65
- :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
66
- dictionary using json.loads().
67
- """
68
- if json_parse_values is None:
69
- json_parse_values = [EventFieldType.LABELS]
70
-
71
- return _mapping_attributes(
72
- model_class=cls,
73
- flattened_dictionary=endpoint_dict,
74
- json_parse_values=json_parse_values,
75
- )
76
-
77
-
78
- class ModelEndpointSpec(ObjectSpec):
79
- function_uri: Optional[str] = "" # <project_name>/<function_name>:<tag>
80
- model: Optional[str] = "" # <model_name>:<version>
81
- model_class: Optional[str] = ""
82
- model_uri: Optional[str] = ""
83
- feature_names: Optional[list[str]] = []
84
- label_names: Optional[list[str]] = []
85
- stream_path: Optional[str] = ""
86
- algorithm: Optional[str] = ""
87
- monitor_configuration: Optional[dict] = {}
88
- active: Optional[bool] = True
89
- monitoring_mode: Optional[ModelMonitoringMode] = ModelMonitoringMode.disabled.value
90
-
91
- @classmethod
92
- def from_flat_dict(
93
- cls, endpoint_dict: dict, json_parse_values: Optional[list] = None
94
- ):
95
- """Create a `ModelEndpointSpec` object from an endpoint dictionary
96
-
97
- :param endpoint_dict: Model endpoint dictionary.
98
- :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
99
- dictionary using json.loads().
100
- """
101
- if json_parse_values is None:
102
- json_parse_values = [
103
- EventFieldType.FEATURE_NAMES,
104
- EventFieldType.LABEL_NAMES,
105
- EventFieldType.MONITOR_CONFIGURATION,
106
- ]
107
- return _mapping_attributes(
108
- model_class=cls,
109
- flattened_dictionary=endpoint_dict,
110
- json_parse_values=json_parse_values,
111
- )
112
-
113
- @validator("model_uri")
114
- @classmethod
115
- def validate_model_uri(cls, model_uri):
116
- """Validate that the model uri includes the required prefix"""
117
- prefix, uri = mlrun.datastore.parse_store_uri(model_uri)
118
- if prefix and prefix != mlrun.utils.helpers.StorePrefix.Model:
119
- return mlrun.datastore.get_store_uri(
120
- mlrun.utils.helpers.StorePrefix.Model, uri
121
- )
122
- return model_uri
123
-
124
-
125
45
  class Histogram(BaseModel):
126
46
  buckets: list[float]
127
47
  counts: list[int]
@@ -167,50 +87,24 @@ class Features(BaseModel):
167
87
  )
168
88
 
169
89
 
170
- class ModelEndpointStatus(ObjectStatus):
171
- feature_stats: Optional[dict] = {}
172
- current_stats: Optional[dict] = {}
173
- first_request: Optional[str] = ""
174
- last_request: Optional[str] = ""
175
- error_count: Optional[int] = 0
176
- drift_status: Optional[str] = ""
177
- drift_measures: Optional[dict] = {}
178
- metrics: Optional[dict[str, dict[str, Any]]] = {
179
- EventKeyMetrics.GENERIC: {
180
- EventLiveStats.LATENCY_AVG_1H: 0,
181
- EventLiveStats.PREDICTIONS_PER_SECOND: 0,
182
- }
183
- }
184
- features: Optional[list[Features]] = []
185
- children: Optional[list[str]] = []
186
- children_uids: Optional[list[str]] = []
187
- endpoint_type: Optional[EndpointType] = EndpointType.NODE_EP
188
- monitoring_feature_set_uri: Optional[str] = ""
189
- state: Optional[str] = ""
190
-
191
- class Config:
192
- extra = Extra.allow
90
+ class ModelEndpointParser(abc.ABC, BaseModel):
91
+ @classmethod
92
+ def json_parse_values(cls) -> list[str]:
93
+ return []
193
94
 
194
95
  @classmethod
195
96
  def from_flat_dict(
196
97
  cls, endpoint_dict: dict, json_parse_values: Optional[list] = None
197
- ):
198
- """Create a `ModelEndpointStatus` object from an endpoint dictionary
98
+ ) -> "ModelEndpointParser":
99
+ """Create a `ModelEndpointParser` object from an endpoint dictionary
199
100
 
200
101
  :param endpoint_dict: Model endpoint dictionary.
201
102
  :param json_parse_values: List of dictionary keys with a JSON string value that will be parsed into a
202
103
  dictionary using json.loads().
203
104
  """
204
105
  if json_parse_values is None:
205
- json_parse_values = [
206
- EventFieldType.FEATURE_STATS,
207
- EventFieldType.CURRENT_STATS,
208
- EventFieldType.DRIFT_MEASURES,
209
- EventFieldType.METRICS,
210
- EventFieldType.CHILDREN,
211
- EventFieldType.CHILDREN_UIDS,
212
- EventFieldType.ENDPOINT_TYPE,
213
- ]
106
+ json_parse_values = cls.json_parse_values()
107
+
214
108
  return _mapping_attributes(
215
109
  model_class=cls,
216
110
  flattened_dictionary=endpoint_dict,
@@ -218,16 +112,53 @@ class ModelEndpointStatus(ObjectStatus):
218
112
  )
219
113
 
220
114
 
115
+ class ModelEndpointMetadata(ObjectMetadata, ModelEndpointParser):
116
+ project: constr(regex=PROJECT_PATTERN)
117
+ endpoint_type: EndpointType = EndpointType.NODE_EP
118
+ uid: Optional[constr(regex=MODEL_ENDPOINT_ID_PATTERN)]
119
+
120
+
121
+ class ModelEndpointSpec(ObjectSpec, ModelEndpointParser):
122
+ model_uid: Optional[str] = ""
123
+ model_name: Optional[str] = ""
124
+ model_tag: Optional[str] = ""
125
+ model_class: Optional[str] = ""
126
+ function_name: Optional[str] = ""
127
+ function_tag: Optional[str] = ""
128
+ function_uid: Optional[str] = ""
129
+ feature_names: Optional[list[str]] = []
130
+ label_names: Optional[list[str]] = []
131
+ feature_stats: Optional[dict] = {}
132
+ function_uri: Optional[str] = "" # <project_name>/<function_hash>
133
+ model_uri: Optional[str] = ""
134
+ children: Optional[list[str]] = []
135
+ children_uids: Optional[list[str]] = []
136
+ monitoring_feature_set_uri: Optional[str] = ""
137
+
138
+
139
+ class ModelEndpointStatus(ObjectStatus, ModelEndpointParser):
140
+ state: Optional[str] = "unknown" # will be updated according to the function state
141
+ first_request: Optional[datetime] = None
142
+ monitoring_mode: Optional[ModelMonitoringMode] = ModelMonitoringMode.disabled
143
+
144
+ # operative
145
+ last_request: Optional[datetime] = None
146
+ result_status: Optional[int] = -1
147
+ avg_latency: Optional[float] = None
148
+ error_count: Optional[int] = 0
149
+ current_stats: Optional[dict] = {}
150
+ current_stats_timestamp: Optional[datetime] = None
151
+ drift_measures: Optional[dict] = {}
152
+ drift_measures_timestamp: Optional[datetime] = None
153
+
154
+
221
155
  class ModelEndpoint(BaseModel):
222
156
  kind: ObjectKind = Field(ObjectKind.model_endpoint, const=True)
223
157
  metadata: ModelEndpointMetadata
224
- spec: ModelEndpointSpec = ModelEndpointSpec()
225
- status: ModelEndpointStatus = ModelEndpointStatus()
158
+ spec: ModelEndpointSpec
159
+ status: ModelEndpointStatus
226
160
 
227
- class Config:
228
- extra = Extra.allow
229
-
230
- def flat_dict(self):
161
+ def flat_dict(self) -> dict[str, Any]:
231
162
  """Generate a flattened `ModelEndpoint` dictionary. The flattened dictionary result is important for storing
232
163
  the model endpoint object in the database.
233
164
 
@@ -235,35 +166,24 @@ class ModelEndpoint(BaseModel):
235
166
  """
236
167
  # Convert the ModelEndpoint object into a dictionary using BaseModel dict() function
237
168
  # In addition, remove the BaseModel kind as it is not required by the DB schema
238
- model_endpoint_dictionary = self.dict(exclude={"kind"})
239
169
 
170
+ model_endpoint_dictionary = self.dict(exclude={"kind"})
171
+ exclude = {
172
+ "tag",
173
+ ModelEndpointSchema.FEATURE_STATS,
174
+ ModelEndpointSchema.CURRENT_STATS,
175
+ ModelEndpointSchema.DRIFT_MEASURES,
176
+ ModelEndpointSchema.FUNCTION_URI,
177
+ ModelEndpointSchema.MODEL_URI,
178
+ }
240
179
  # Initialize a flattened dictionary that will be filled with the model endpoint dictionary attributes
241
180
  flatten_dict = {}
242
181
  for k_object in model_endpoint_dictionary:
243
182
  for key in model_endpoint_dictionary[k_object]:
244
- # Extract the value of the current field
245
- current_value = model_endpoint_dictionary[k_object][key]
246
-
247
- # If the value is not from type str or bool (e.g. dict), convert it into a JSON string
248
- # for matching the database required format
249
- if not isinstance(current_value, (str, bool, int)) or isinstance(
250
- current_value, enum.IntEnum
251
- ):
252
- flatten_dict[key] = json.dumps(current_value)
253
- else:
254
- flatten_dict[key] = current_value
255
-
256
- if EventFieldType.METRICS not in flatten_dict:
257
- # Initialize metrics dictionary
258
- flatten_dict[EventFieldType.METRICS] = {
259
- EventKeyMetrics.GENERIC: {
260
- EventLiveStats.LATENCY_AVG_1H: 0,
261
- EventLiveStats.PREDICTIONS_PER_SECOND: 0,
262
- }
263
- }
264
-
265
- # Remove the features from the dictionary as this field will be filled only within the feature analysis process
266
- flatten_dict.pop(EventFieldType.FEATURES, None)
183
+ if key not in exclude:
184
+ # Extract the value of the current field
185
+ flatten_dict[key] = model_endpoint_dictionary[k_object][key]
186
+
267
187
  return flatten_dict
268
188
 
269
189
  @classmethod
@@ -280,9 +200,17 @@ class ModelEndpoint(BaseModel):
280
200
  status=ModelEndpointStatus.from_flat_dict(endpoint_dict=endpoint_dict),
281
201
  )
282
202
 
203
+ def get(self, field, default=None):
204
+ return (
205
+ getattr(self.metadata, field, None)
206
+ or getattr(self.spec, field, None)
207
+ or getattr(self.status, field, None)
208
+ or default
209
+ )
210
+
283
211
 
284
212
  class ModelEndpointList(BaseModel):
285
- endpoints: list[ModelEndpoint] = []
213
+ endpoints: list[ModelEndpoint]
286
214
 
287
215
 
288
216
  class ModelEndpointMonitoringMetric(BaseModel):
@@ -132,8 +132,14 @@ class SetNotificationRequest(pydantic.v1.BaseModel):
132
132
  notifications: list[Notification] = None
133
133
 
134
134
 
135
+ class NotificationSummary(pydantic.v1.BaseModel):
136
+ failed: int = 0
137
+ succeeded: int = 0
138
+
139
+
135
140
  class NotificationState(pydantic.v1.BaseModel):
136
141
  kind: str
137
142
  err: Optional[
138
143
  str
139
144
  ] # empty error means that the notifications were sent successfully
145
+ summary: NotificationSummary
@@ -159,6 +159,9 @@ class ProjectSummary(pydantic.v1.BaseModel):
159
159
  pipelines_failed_recent_count: typing.Optional[int] = None
160
160
  pipelines_running_count: typing.Optional[int] = None
161
161
  updated: typing.Optional[datetime.datetime] = None
162
+ endpoint_alerts_count: int = 0
163
+ job_alerts_count: int = 0
164
+ other_alerts_count: int = 0
162
165
 
163
166
 
164
167
  class IguazioProject(pydantic.v1.BaseModel):
mlrun/config.py CHANGED
@@ -136,7 +136,7 @@ default_config = {
136
136
  },
137
137
  },
138
138
  "object_retentions": {
139
- "alert_activation": 14 * 7, # days
139
+ "alert_activations": 14 * 7, # days
140
140
  },
141
141
  # A safety margin to account for delays
142
142
  # This ensures that extra partitions are available beyond the specified retention period
@@ -232,6 +232,7 @@ default_config = {
232
232
  "delete_function": "900",
233
233
  },
234
234
  "runtimes": {"dask": "600"},
235
+ "push_notifications": "60",
235
236
  },
236
237
  },
237
238
  "function": {
@@ -607,8 +608,6 @@ default_config = {
607
608
  "default_http_sink_app": "http://nuclio-{project}-{application_name}.{namespace}.svc.cluster.local:8080",
608
609
  "parquet_batching_max_events": 10_000,
609
610
  "parquet_batching_timeout_secs": timedelta(minutes=1).total_seconds(),
610
- # See mlrun.model_monitoring.db.stores.ObjectStoreFactory for available options
611
- "endpoint_store_connection": "",
612
611
  # See mlrun.model_monitoring.db.tsdb.ObjectTSDBFactory for available options
613
612
  "tsdb_connection": "",
614
613
  # See mlrun.common.schemas.model_monitoring.constants.StreamKind for available options
@@ -81,22 +81,62 @@ class DatastoreProfileBasic(DatastoreProfile):
81
81
  private: typing.Optional[str] = None
82
82
 
83
83
 
84
- class VectorStoreProfile(DatastoreProfile):
85
- type: str = pydantic.Field("vector")
86
- _private_attributes = ("kwargs_private",)
87
- vector_store_class: str
88
- kwargs_public: typing.Optional[dict] = None
89
- kwargs_private: typing.Optional[dict] = None
90
-
91
- def attributes(self, kwargs=None):
92
- attributes = {}
93
- if self.kwargs_public:
94
- attributes = merge(attributes, self.kwargs_public)
95
- if self.kwargs_private:
96
- attributes = merge(attributes, self.kwargs_private)
97
- if kwargs:
98
- attributes = merge(attributes, kwargs)
99
- return attributes
84
+ class ConfigProfile(DatastoreProfile):
85
+ """
86
+ A profile class for managing configuration data with nested public and private attributes.
87
+ This class extends DatastoreProfile to handle configuration settings, separating them into
88
+ public and private dictionaries. Both dictionaries support nested structures, and the class
89
+ provides functionality to merge these attributes when needed.
90
+
91
+ Args:
92
+ public (Optional[dict]): Dictionary containing public configuration settings,
93
+ supporting nested structures
94
+ private (Optional[dict]): Dictionary containing private/sensitive configuration settings,
95
+ supporting nested structures
96
+
97
+ Example:
98
+ >>> public = {
99
+ "database": {
100
+ "host": "localhost",
101
+ "port": 5432
102
+ },
103
+ "api_version": "v1"
104
+ }
105
+ >>> private = {
106
+ "database": {
107
+ "password": "secret123",
108
+ "username": "admin"
109
+ },
110
+ "api_key": "xyz789"
111
+ }
112
+ >>> config = ConfigProfile("myconfig", public=public, private=private)
113
+
114
+ # When attributes() is called, it merges public and private:
115
+ # {
116
+ # "database": {
117
+ # "host": "localhost",
118
+ # "port": 5432,
119
+ # "password": "secret123",
120
+ # "username": "admin"
121
+ # },
122
+ # "api_version": "v1",
123
+ # "api_key": "xyz789"
124
+ # }
125
+
126
+ """
127
+
128
+ type = "config"
129
+ _private_attributes = "private"
130
+ public: typing.Optional[dict] = None
131
+ private: typing.Optional[dict] = None
132
+
133
+ def attributes(self):
134
+ res = {}
135
+ if self.public:
136
+ res = merge(res, self.public)
137
+ if self.private:
138
+ res = merge(res, self.private)
139
+ return res
100
140
 
101
141
 
102
142
  class DatastoreProfileKafkaTarget(DatastoreProfile):
@@ -494,7 +534,7 @@ class DatastoreProfile2Json(pydantic.v1.BaseModel):
494
534
  "gcs": DatastoreProfileGCS,
495
535
  "az": DatastoreProfileAzureBlob,
496
536
  "hdfs": DatastoreProfileHdfs,
497
- "vector": VectorStoreProfile,
537
+ "config": ConfigProfile,
498
538
  }
499
539
  if datastore_type in ds_profile_factory:
500
540
  return ds_profile_factory[datastore_type].parse_obj(decoded_dict)
@@ -951,8 +951,7 @@ class OnlineSource(BaseSourceDriver):
951
951
  is_explicit_ack_supported(context)
952
952
  and mlrun.mlconf.is_explicit_ack_enabled()
953
953
  )
954
- # TODO: Change to AsyncEmitSource once we can drop support for nuclio<1.12.10
955
- src_class = storey.SyncEmitSource(
954
+ src_class = storey.AsyncEmitSource(
956
955
  context=context,
957
956
  key_field=self.key_field or key_field,
958
957
  full_event=True,