@@ -202,6 +202,10 @@ class SqlRegistryConfig(RegistryConfig):
202
202
""" str: Path to metadata store.
203
203
If registry_type is 'sql', then this is a database URL as expected by SQLAlchemy """
204
204
205
+ read_path : Optional [StrictStr ] = None
206
+ """ str: Read Path to metadata store if different from path.
207
+ If registry_type is 'sql', then this is a Read Endpoint for database URL. If not set, path will be used for read and write. """
208
+
205
209
sqlalchemy_config_kwargs : Dict [str , Any ] = {"echo" : False }
206
210
""" Dict[str, Any]: Extra arguments to pass to SQLAlchemy.create_engine. """
207
211
@@ -223,13 +227,20 @@ def __init__(
223
227
registry_config , SqlRegistryConfig
224
228
), "SqlRegistry needs a valid registry_config"
225
229
226
- self .engine : Engine = create_engine (
230
+ self .write_engine : Engine = create_engine (
227
231
registry_config .path , ** registry_config .sqlalchemy_config_kwargs
228
232
)
233
+ if registry_config .read_path :
234
+ self .read_engine : Engine = create_engine (
235
+ registry_config .read_path ,
236
+ ** registry_config .sqlalchemy_config_kwargs ,
237
+ )
238
+ else :
239
+ self .read_engine = self .write_engine
240
+ metadata .create_all (self .write_engine )
229
241
self .thread_pool_executor_worker_count = (
230
242
registry_config .thread_pool_executor_worker_count
231
243
)
232
- metadata .create_all (self .engine )
233
244
self .purge_feast_metadata = registry_config .purge_feast_metadata
234
245
# Sync feast_metadata to projects table
235
246
# when purge_feast_metadata is set to True, Delete data from
@@ -246,7 +257,7 @@ def __init__(
246
257
def _sync_feast_metadata_to_projects_table (self ):
247
258
feast_metadata_projects : set = []
248
259
projects_set : set = []
249
- with self .engine .begin () as conn :
260
+ with self .write_engine .begin () as conn :
250
261
stmt = select (feast_metadata ).where (
251
262
feast_metadata .c .metadata_key == FeastMetadataKeys .PROJECT_UUID .value
252
263
)
@@ -255,7 +266,7 @@ def _sync_feast_metadata_to_projects_table(self):
255
266
feast_metadata_projects .append (row ._mapping ["project_id" ])
256
267
257
268
if len (feast_metadata_projects ) > 0 :
258
- with self .engine .begin () as conn :
269
+ with self .write_engine .begin () as conn :
259
270
stmt = select (projects )
260
271
rows = conn .execute (stmt ).all ()
261
272
for row in rows :
@@ -267,7 +278,7 @@ def _sync_feast_metadata_to_projects_table(self):
267
278
self .apply_project (Project (name = project_name ), commit = True )
268
279
269
280
if self .purge_feast_metadata :
270
- with self .engine .begin () as conn :
281
+ with self .write_engine .begin () as conn :
271
282
for project_name in feast_metadata_projects :
272
283
stmt = delete (feast_metadata ).where (
273
284
feast_metadata .c .project_id == project_name
@@ -285,7 +296,7 @@ def teardown(self):
285
296
validation_references ,
286
297
permissions ,
287
298
}:
288
- with self .engine .begin () as conn :
299
+ with self .write_engine .begin () as conn :
289
300
stmt = delete (t )
290
301
conn .execute (stmt )
291
302
@@ -549,7 +560,7 @@ def apply_feature_service(
549
560
)
550
561
551
562
def delete_data_source (self , name : str , project : str , commit : bool = True ):
552
- with self .engine .begin () as conn :
563
+ with self .write_engine .begin () as conn :
553
564
stmt = delete (data_sources ).where (
554
565
data_sources .c .data_source_name == name ,
555
566
data_sources .c .project_id == project ,
@@ -607,7 +618,7 @@ def _list_on_demand_feature_views(
607
618
)
608
619
609
620
def _list_project_metadata (self , project : str ) -> List [ProjectMetadata ]:
610
- with self .engine .begin () as conn :
621
+ with self .read_engine .begin () as conn :
611
622
stmt = select (feast_metadata ).where (
612
623
feast_metadata .c .project_id == project ,
613
624
)
@@ -726,7 +737,7 @@ def apply_user_metadata(
726
737
table = self ._infer_fv_table (feature_view )
727
738
728
739
name = feature_view .name
729
- with self .engine .begin () as conn :
740
+ with self .write_engine .begin () as conn :
730
741
stmt = select (table ).where (
731
742
getattr (table .c , "feature_view_name" ) == name ,
732
743
table .c .project_id == project ,
@@ -781,7 +792,7 @@ def get_user_metadata(
781
792
table = self ._infer_fv_table (feature_view )
782
793
783
794
name = feature_view .name
784
- with self .engine .begin () as conn :
795
+ with self .read_engine .begin () as conn :
785
796
stmt = select (table ).where (getattr (table .c , "feature_view_name" ) == name )
786
797
row = conn .execute (stmt ).first ()
787
798
if row :
@@ -885,7 +896,7 @@ def _apply_object(
885
896
name = name or (obj .name if hasattr (obj , "name" ) else None )
886
897
assert name , f"name needs to be provided for { obj } "
887
898
888
- with self .engine .begin () as conn :
899
+ with self .write_engine .begin () as conn :
889
900
update_datetime = _utc_now ()
890
901
update_time = int (update_datetime .timestamp ())
891
902
stmt = select (table ).where (
@@ -961,7 +972,7 @@ def _apply_object(
961
972
962
973
def _maybe_init_project_metadata (self , project ):
963
974
# Initialize project metadata if needed
964
- with self .engine .begin () as conn :
975
+ with self .write_engine .begin () as conn :
965
976
update_datetime = _utc_now ()
966
977
update_time = int (update_datetime .timestamp ())
967
978
stmt = select (feast_metadata ).where (
@@ -988,7 +999,7 @@ def _delete_object(
988
999
id_field_name : str ,
989
1000
not_found_exception : Optional [Callable ],
990
1001
):
991
- with self .engine .begin () as conn :
1002
+ with self .write_engine .begin () as conn :
992
1003
stmt = delete (table ).where (
993
1004
getattr (table .c , id_field_name ) == name , table .c .project_id == project
994
1005
)
@@ -1014,7 +1025,7 @@ def _get_object(
1014
1025
proto_field_name : str ,
1015
1026
not_found_exception : Optional [Callable ],
1016
1027
):
1017
- with self .engine .begin () as conn :
1028
+ with self .read_engine .begin () as conn :
1018
1029
stmt = select (table ).where (
1019
1030
getattr (table .c , id_field_name ) == name , table .c .project_id == project
1020
1031
)
@@ -1036,7 +1047,7 @@ def _list_objects(
1036
1047
proto_field_name : str ,
1037
1048
tags : Optional [dict [str , str ]] = None ,
1038
1049
):
1039
- with self .engine .begin () as conn :
1050
+ with self .read_engine .begin () as conn :
1040
1051
stmt = select (table ).where (table .c .project_id == project )
1041
1052
rows = conn .execute (stmt ).all ()
1042
1053
if rows :
@@ -1051,7 +1062,7 @@ def _list_objects(
1051
1062
return []
1052
1063
1053
1064
def _set_last_updated_metadata (self , last_updated : datetime , project : str ):
1054
- with self .engine .begin () as conn :
1065
+ with self .write_engine .begin () as conn :
1055
1066
stmt = select (feast_metadata ).where (
1056
1067
feast_metadata .c .metadata_key
1057
1068
== FeastMetadataKeys .LAST_UPDATED_TIMESTAMP .value ,
@@ -1085,7 +1096,7 @@ def _set_last_updated_metadata(self, last_updated: datetime, project: str):
1085
1096
conn .execute (insert_stmt )
1086
1097
1087
1098
def _get_last_updated_metadata (self , project : str ):
1088
- with self .engine .begin () as conn :
1099
+ with self .read_engine .begin () as conn :
1089
1100
stmt = select (feast_metadata ).where (
1090
1101
feast_metadata .c .metadata_key
1091
1102
== FeastMetadataKeys .LAST_UPDATED_TIMESTAMP .value ,
@@ -1130,7 +1141,7 @@ def apply_permission(
1130
1141
)
1131
1142
1132
1143
def delete_permission (self , name : str , project : str , commit : bool = True ):
1133
- with self .engine .begin () as conn :
1144
+ with self .write_engine .begin () as conn :
1134
1145
stmt = delete (permissions ).where (
1135
1146
permissions .c .permission_name == name ,
1136
1147
permissions .c .project_id == project ,
@@ -1143,7 +1154,7 @@ def _list_projects(
1143
1154
self ,
1144
1155
tags : Optional [dict [str , str ]],
1145
1156
) -> List [Project ]:
1146
- with self .engine .begin () as conn :
1157
+ with self .read_engine .begin () as conn :
1147
1158
stmt = select (projects )
1148
1159
rows = conn .execute (stmt ).all ()
1149
1160
if rows :
@@ -1188,7 +1199,7 @@ def delete_project(
1188
1199
):
1189
1200
project = self .get_project (name , allow_cache = False )
1190
1201
if project :
1191
- with self .engine .begin () as conn :
1202
+ with self .write_engine .begin () as conn :
1192
1203
for t in {
1193
1204
managed_infra ,
1194
1205
saved_datasets ,
0 commit comments