Visitar URL original
feat(server): Remote Materialization by aniketpalu · Pull Request #6649 · feast-dev/feast · GitHub
Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(server): Let store own MATERIALIZING transitions on async path
Remove server-side MATERIALIZING pre-set before 202 which conflicted with
store.materialize() state machine (MATERIALIZING → MATERIALIZING rejected).
Async now accepts and runs materialize in the background; store owns
transitions. ?force=true resets stuck MATERIALIZING FVs to GENERATED so
normal materialize can proceed.

Signed-off-by: Aniket Paluskar <apaluska@redhat.com>
  • Loading branch information
aniketpalu committed Jul 28, 2026
commit b5cb173cb6f789abfb35c071f539bc80696db976
40 changes: 34 additions & 6 deletions sdk/python/feast/feature_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,31 @@ def _update_fv_state(
logger.warning(f"Failed to set state={state} for {fv_name}")


def _reset_stuck_materializing_to_generated(
store: "feast.FeatureStore",
fv_names: List[str],
) -> None:
"""Reset FVs currently in MATERIALIZING to GENERATED (force override).

Leaves other states untouched so store.materialize() can transition normally.
"""
stuck: List[str] = []
for fv_name in fv_names:
try:
fv = store.registry.get_feature_view(
fv_name, store.project, allow_cache=False
)
if getattr(fv, "state", None) == FeatureViewState.MATERIALIZING:
stuck.append(fv_name)
except Exception:
pass
if stuck:
_update_fv_state(store, stuck, FeatureViewState.GENERATED)
logger.info(
"Force reset MATERIALIZING → GENERATED for feature views: %s", stuck
)


def _parse_materialize_timestamps(
request: "MaterializeRequest",
) -> tuple:
Expand Down Expand Up @@ -902,13 +927,15 @@ async def materialize(
start_date, end_date = _parse_materialize_timestamps(request)

if async_mode:
if not force:
if force:
_reset_stuck_materializing_to_generated(store, fv_names)
else:
conflict = _check_already_materializing(store, fv_names)
if conflict:
return conflict

_update_fv_state(store, fv_names, FeatureViewState.MATERIALIZING)

# State transitions (MATERIALIZING / AVAILABLE_ONLINE) are owned
# by store.materialize(); server only accepts and runs in background.
def _run_materialize():
try:
store.materialize(
Expand Down Expand Up @@ -954,13 +981,14 @@ async def materialize_incremental(
end_date = utils.make_tzaware(parser.parse(request.end_ts))

if async_mode:
if not force:
if force:
_reset_stuck_materializing_to_generated(store, fv_names)
else:
conflict = _check_already_materializing(store, fv_names)
if conflict:
return conflict

_update_fv_state(store, fv_names, FeatureViewState.MATERIALIZING)

# State transitions owned by store.materialize_incremental().
def _run_materialize_incremental():
try:
store.materialize_incremental(
Expand Down
Loading