Skip to content

Conversation

@keelerm84
Copy link
Member

@keelerm84 keelerm84 commented Oct 23, 2025

Note

Adds FDv2 persistent store integration (read-only/read-write), data store status monitoring, and comprehensive tests.

  • FDv2 & Store:

    • Integrate optional persistent FeatureStore with Store.with_persistence(...); respect DataStoreMode.READ_ONLY vs READ_WRITE for writes.
    • Add FeatureStoreClientWrapper to sort init data and emit DataStoreStatus availability updates with recovery polling.
    • Persist data on full transfers and deltas when writable; implement commit(); replace prints with log.
  • Configuration:

    • Extend DataSystemConfig with data_store_mode and optional data_store; make primary_synchronizer optional.
    • Add ConfigBuilder.data_store(...); provide daemon(...) (read-only) and persistent_store(...) (read-write) helpers.
    • Introduce DataStoreMode enum.
  • Status APIs:

    • Implement DataStoreStatusProviderImpl with listener support and monitoring detection.
    • Enhance DataStoreStatus with equality semantics.
  • Tests:

    • Add test_fdv2_persistence.py covering read-only/write modes, delta and delete persistence, and status provider/monitoring.
    • Update config builder tests to reflect optional primary synchronizer and new defaults.

Written by Cursor Bugbot for commit e88a705. This will update automatically on new commits. Configure here.

@keelerm84 keelerm84 requested a review from a team as a code owner October 23, 2025 16:46
@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Deadlock Risk in FeatureStoreClientWrapper

In FeatureStoreClientWrapper.__update_availability, the lock acquired before self.__poller.start() isn't released if start() raises an exception. This missing try/finally block can lead to a deadlock, contrasting with other lock usages in the method.

Additional Locations (1)

Fix in Cursor Fix in Web

self.__lock.unlock()

if modified:
self.__listeners.notify(status)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the threading situation like for this dispatch? Is the caller thread always the same thread?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, unfortunately that's the way the current listeners work in python. The notify method itself catches all exceptions, which is why we aren't doing it here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Well it is good in a sense, because it helps prevent out of order handling from unfortunate thread context switching. If it was multi-threaded, then I would be concerned we would need some async queue type situation.

"""
update_status is called from the data store to push a status update.
"""
self.__lock.lock()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this has to use lock/unlock vs with?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the LD provided RW lock. There is no context usage for this class.

Base automatically changed from mk/sdk-1419/fdv2-datasystem-impl to feat/fdv2 October 30, 2025 19:40
@keelerm84 keelerm84 force-pushed the mk/sdk-1504/persistence branch from 4e44909 to e88a705 Compare October 30, 2025 19:43
self.__status = status
modified = True

self.__lock.unlock()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Deadlock Risk in FeatureStoreClientWrapper

In FeatureStoreClientWrapper.__update_availability, the ReadWriteLock may not be released if an exception occurs after acquisition. This happens in two places: when updating __last_available and when starting self.__poller, which could lead to a deadlock.

Additional Locations (1)

Fix in Cursor Fix in Web

def status(self) -> DataStoreStatus:
self.__lock.rlock()
status = copy(self.__status)
self.__lock.runlock()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Locking Issue in DataStore Status Handling

The DataStoreStatusProviderImpl.status property's rlock/runlock pattern is not exception-safe. If copy(self.__status) raises an exception, the read lock remains held, potentially causing a deadlock.

Fix in Cursor Fix in Web

@keelerm84 keelerm84 merged commit 8dd4c89 into feat/fdv2 Oct 30, 2025
23 of 24 checks passed
@keelerm84 keelerm84 deleted the mk/sdk-1504/persistence branch October 30, 2025 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants